//#include "stdafx.h"
#include "ProposalTree.h"

// [*] CMyTreeInstance

double CMyTreeInstance::s_DetectionNMS_AOP_Thrshold;

int CMyTreeInstance::DoDetectionNMS(
	CSimpleTypeArray<CMyTreeInstance>& DstReducedDetectionList,
	CSimpleTypeArray<CMyTreeInstance>& SrcOriginalDetectionList
	)
{
	int i, j;
	double AOP;

	DstReducedDetectionList.Clear();
	sort(SrcOriginalDetectionList.Begin(), SrcOriginalDetectionList.End());
	for ( i = 0; i < (int)SrcOriginalDetectionList.Size; ++i )
	{
		CMyTreeInstance& iMTI = SrcOriginalDetectionList.pElement[i];
		for ( j = 0; j < (int)DstReducedDetectionList.Size; ++j )
		{
			CMyTreeInstance& jMTI = DstReducedDetectionList.pElement[j];
			AOP = CRectBox<double>::CalcAO_Percent(iMTI.DetectionBox, jMTI.DetectionBox);
			if (AOP > s_DetectionNMS_AOP_Thrshold) break;
		}
		if (j < (int)DstReducedDetectionList.Size) continue;
		DstReducedDetectionList.PushBack(iMTI);
	}
	return (int)DstReducedDetectionList.Size;
}

//CImageFilterBank* CProposalTree::pImageFilterBank;

bool SortByThresInstScore(InstThresType &p1, InstThresType &p2)
{
	return p1.Score > p2.Score;
}

CProposalTree::CProposalTree(void)
{
	//root	= 0;
}

CProposalTree::~CProposalTree(void)
{
}

inline double CProposalTree::OriDiff(double ori1, double ori2)				// [-PI, PI]
{
	double	ori	= ori2 - ori1;

	while ( ori > M_PI )
	{
		ori -= M_PI * 2;
	}

	while ( ori < - M_PI )
	{
		ori	+= M_PI * 2;
	}

	return	ori;
}

int	CProposalTree::SaveAndOrTreeModel(string strAndOrTreeFileName)
{
	FILE		*fpFile;
	errno_t		err;
	int			AndNodeCount	= (int) model.AndModels.size();
	int			OrNodeCount		= (int) model.OrModels.size();
	int			LeafNodeCount	= (int) model.LeafModels.size();
	int			ret;

	err	= fopen_s(&fpFile, strAndOrTreeFileName.c_str(), "w");

	// basic information
	fprintf_s(fpFile, "%6d %6d %6d\n\n", model.Root, model.MaxLevel, (int) model.Rules.size());

	// and nodes
	fprintf_s(fpFile, "%d\n", AndNodeCount);
	for ( int i = 0; i < AndNodeCount; i++ )
	{
		ret	= model.AndModels[i].SaveAndNodeModel(fpFile, (int) model.Rules.size());
	}

	// or nodes
	fprintf_s(fpFile, "%d\n", OrNodeCount);
	for ( int i = 0; i < OrNodeCount; i++ )
	{
		ret	= model.OrModels[i].SaveOrNodeModel(fpFile);
	}

	// leaf nodes
	fprintf_s(fpFile, "%d\n", LeafNodeCount);
	for ( int i = 0; i < LeafNodeCount; i++ )
	{
		ret	= model.LeafModels[i].SaveLeafNodeModel(fpFile);
	}

	// Leaf Node Information
	for ( int i = 0; i < LeafNodeCount; i++ )
	{
		for ( int j = 0; j < LeafNodeCount; j++ )
		{
			fprintf(fpFile, "%12.6f", model.LeafLenInfo[i][j]);
		}
		fprintf(fpFile, "\n");
	}
	for ( int i = 0; i < LeafNodeCount; i++ )
	{
		for ( int j = 0; j < LeafNodeCount; j++ )
		{
			fprintf(fpFile, "%12.6f", model.LeafDirInfo[i][j]);
		}
		fprintf(fpFile, "\n");
	}

	fprintf_s(fpFile, "%d\n", (int)model.Curves.size());
	for ( int i = 0; i < (int) model.Curves.size(); i++ )
	{
		fprintf_s(fpFile, "%d	%d	", model.Curves[i].LeafID1, model.Curves[i].LeafID2);
		fprintf_s(fpFile, "%12.6f	%12.6f	", model.Curves[i].NodeLen, model.Curves[i].NodeDir);
		fprintf_s(fpFile, "%d\n", (int) model.Curves[i].Curve.size());
		for ( int j = 0; j < (int)model.Curves[i].Curve.size(); j++ )
		{
			fprintf_s(fpFile, "%12.6f%12.6f%12.6f\n", model.Curves[i].Curve[j].pos_len, model.Curves[i].Curve[j].pos_ori, model.Curves[i].Curve[j].dir);
		}
	}

	fprintf_s(fpFile, "\n");
	for ( int i = 0; i < (int) model.Rules.size(); i++ )
	{
		fprintf_s(fpFile, "%6d", model.Rules[i].ArcType);
		switch (model.Rules[i].ArcType)
		{
			case	-1:
				break;
			case	0:
				fprintf_s(fpFile, "%6d", model.Rules[i].RootID);
				fprintf_s(fpFile, "%6d%6d", model.Rules[i].LeafID1, model.Rules[i].LeafID2);
				fprintf_s(fpFile, "%12.6f%12.6f", model.Rules[i].ScaleWeight, model.Rules[i].RotWeight);
				break;
			default:
				break;
		}
		fprintf_s(fpFile, "\n");
	}

	fclose(fpFile);
	return	1;
}

int	CProposalTree::ReadAndOrTreeModel(string strAndOrTreeFileName)
{
	FILE		*fpFile;
	errno_t		err;
	int			AndNodeCount, OrNodeCount, LeafNodeCount;
	int			CurveCount, CurveLen;
	int			RuleCount;
	int			ret;

	err	= fopen_s(&fpFile, strAndOrTreeFileName.c_str(), "r");

	// basic information
	fscanf_s(fpFile, "%d%d%d", &model.Root, &model.MaxLevel, &RuleCount);

	// And Node
	fscanf_s(fpFile, "%d", &AndNodeCount);
	model.AndModels.resize(AndNodeCount);
	for ( int i = 0; i < AndNodeCount; i++ )
	{
		ret	= model.AndModels[i].ReadAndNodeModel(fpFile, RuleCount);
	}

	// Or Node
	fscanf_s(fpFile, "%d", &OrNodeCount);
	model.OrModels.resize(OrNodeCount);
	for ( int i = 0; i < OrNodeCount; i++ )
	{
		ret	= model.OrModels[i].ReadOrNodeModel(fpFile);
	}

	// Leaf Node
	fscanf_s(fpFile, "%d", &LeafNodeCount);
	model.LeafModels.resize(LeafNodeCount);
	for ( int i = 0; i < LeafNodeCount; i++ )
	{
		ret	= model.LeafModels[i].ReadLeafNodeModel(fpFile);
	}

	// Leaf Node Information
	model.LeafLenInfo.alloc(LeafNodeCount, LeafNodeCount);
	model.LeafDirInfo.alloc(LeafNodeCount, LeafNodeCount);
	for ( int i = 0; i < LeafNodeCount; i++ )
	{
		for ( int j = 0; j < LeafNodeCount; j++ )
		{
			fscanf_s(fpFile, "%lf", &model.LeafLenInfo[i][j]);
		}
	}
	for ( int i = 0; i < LeafNodeCount; i++ )
	{
		for ( int j = 0; j < LeafNodeCount; j++ )
		{
			fscanf_s(fpFile, "%lf", &model.LeafDirInfo[i][j]);
		}
	}

	// Read Curve Information
	fscanf_s(fpFile, "%d", &CurveCount);
	model.Curves.resize(CurveCount);
	for ( int i = 0; i < CurveCount; i++ )
	{
		fscanf_s(fpFile, "%d%d", &model.Curves[i].LeafID1, &model.Curves[i].LeafID2);
		fscanf_s(fpFile, "%lf%lf", &model.Curves[i].NodeLen, &model.Curves[i].NodeDir);
		fscanf_s(fpFile, "%d", &CurveLen);
		model.Curves[i].Curve.resize(CurveLen);
		for ( int j = 0; j < CurveLen; j++ )
		{
			fscanf_s(fpFile, "%lf%lf%lf", &model.Curves[i].Curve[j].pos_len, &model.Curves[i].Curve[j].pos_ori, &model.Curves[i].Curve[j].dir);
		}
	}

	// Read Rules
	model.Rules.resize(RuleCount);
	for ( int i = 0; i < RuleCount; i++ )
	{
		fscanf_s(fpFile, "%d", &model.Rules[i].ArcType);
		switch (model.Rules[i].ArcType)
		{
			case	-1:
				break;
			case	0:
				fscanf_s(fpFile, "%d", &model.Rules[i].RootID);
				fscanf_s(fpFile, "%d%d", &model.Rules[i].LeafID1, &model.Rules[i].LeafID2);
				fscanf_s(fpFile, "%lf%lf", &model.Rules[i].ScaleWeight, &model.Rules[i].RotWeight);
				break;
			default:
				break;
		}
	}
	model.RuleStep = 1;

	fclose(fpFile);
	return	1;
}

//int	CProposalTree::DrawInstanceNode(CHiBoostImageEntity &entity, InstanceTreeType &TreeInstance, string strImageFileName, int NodeIndex)
//{
//	CImageEx			*pImage, *pOImage;
//	RGBQUAD				*pBits, *pRGB;
//	vector<Color>		colors	= g_Parameter.Colors;
//	//int					LeafID;
//	int					ret;
//
//	// load pImage
//	pOImage	= new CImageEx();
//	pOImage->Load(entity.strImageFileName.c_str());
//	pOImage->ConvertToARGB32Bits();
//	pBits	= (RGBQUAD*) pOImage->GetBits();
//
//	// Draw Background Image
//	pImage				= new CImageEx();
//	pImage->m_pBitmap	= new Bitmap(entity.W, entity.H, PixelFormat32bppPARGB);
//	pRGB				= (RGBQUAD*) pImage->GetBits();
//	for ( int i = 0; i < entity.H; i++ )
//	{
//		for ( int j = 0; j < entity.W; j++, pRGB++, pBits++ )
//		{
//			pRGB->rgbBlue		= pBits->rgbBlue / 2 + 128;
//			pRGB->rgbGreen		= pBits->rgbGreen / 2 + 128;
//			pRGB->rgbRed		= pBits->rgbRed / 2 + 128;
//			pRGB->rgbReserved	= pBits->rgbReserved;
//		}
//	}
//	pImage->FreeBits();
//	pOImage->FreeBits();
//	pOImage->Unload();
//	delete	pOImage;
//
//	Graphics		graphics(pImage->m_pBitmap);
//	SolidBrush		myBrush(Color(0, 0, 0));
//	Pen				myPen(&myBrush, 2);
//	Font			myFont(L"Arial Narrow", 12, FontStyleBold);
//	wstring			strShowString;
//	char			szShowText[MAX_PATH];
//	PointF			point;
//
//	myPen.SetWidth(3);
//	for ( int i = 0; i < (int)TreeInstance.AndNodes[NodeIndex].instances.size(); ++i)//   Instance.LeafNodeInfo.size(); i++ )
//	{
//		//LeafID	= Instance.LeafNodeInfo[i].LeafNodeIndex;
//
//		myBrush.SetColor(colors[NodeIndex % colors.size()]);
//		myPen.SetColor(colors[NodeIndex % colors.size()]);
//
//		point.X	= (float) TreeInstance.AndNodes[NodeIndex].instances[i].center.x;// Instance.LeafNodeInfo[i].node.x;
//		point.Y	= (float) TreeInstance.AndNodes[NodeIndex].instances[i].center.y;// Instance.LeafNodeInfo[i].node.y;
//		graphics.DrawEllipse(&myPen,   (int) (point.X - 3), (int) (point.Y - 3), (int) (2*1+1), (int) (2*1+1));
//		graphics.FillEllipse(&myBrush, (int) (point.X - 3), (int) (point.Y - 3), (int) (2*1+1), (int) (2*1+1));
//	}
//
//	myPen.SetColor(Color(255, 0, 0));
//	myBrush.SetColor(Color(255, 0, 0));
//	sprintf_s(szShowText, MAX_PATH, "Amount: %d", (int)TreeInstance.AndNodes[NodeIndex].instances.size());
//	strShowString	= UTF82WChar( (const BYTE *)szShowText, (int) strlen(szShowText) );
//	point.X	= (float) (entity.W - 8 * strlen(szShowText));
//	point.Y	= (float) (entity.H - 20);
//	graphics.DrawString(strShowString.c_str(), (int) strShowString.length(), &myFont, point, &myBrush);
//
//	// Save Image
//	ret	= pImage->Save(strImageFileName.c_str());
//	delete	pImage;
//
//	return	1;
//}

int	CProposalTree::DrawInstance(CHiBoostImageEntity &entity, NodeInstanceType &Instance, string strImageFileName)
{
	CImg<int> imgOutput;
	char strTemp[10001];

	imgOutput = entity.CurrentImageLayer.imgScaled;

	int i;
	for ( i = (int)imgOutput.size()-1; i >= 0; --i )
		imgOutput.data[i] = imgOutput.data[i]/2 + 128;
	int leaf_index;
	int ix, iy;
	for ( i = 0; i < (int) Instance.LeafNodeInfo.size(); i++ )
	{
		leaf_index	= Instance.LeafNodeInfo[i].LeafNodeIndex;
		ix = (int)Instance.LeafNodeInfo[i].node.x;
		iy = (int)Instance.LeafNodeInfo[i].node.y;
		const Color& _color = g_Parameter.Colors[leaf_index % g_Parameter.Colors.size()];
		imgOutput.draw_circle(
			ix, iy, g_Parameter.PointRadiusForDrawing,
			CExternalTools::GetIntArrayRGB(_color.GetValue() & 0x00ffffff));
	}
	sprintf_s(strTemp, "Score: %.6lf", Instance.Score);
	CExternalTools::OutputTextToImage(imgOutput, strTemp, 8, imgOutput.height - 20, 255, 255, 255, 255, 0, 0);

	CExternalTools::mySaveImage(strImageFileName, imgOutput);

	////CImageEx			*pImage, *pOImage;
	////RGBQUAD				*pBits, *pRGB;
	////vector<Color>		colors	= g_Parameter.Colors;
	////int					LeafID;
	////int					ret;

	////// load pImage
	////pOImage	= new CImageEx();

	////CExternalTools::MakeCImageExInstance(*pOImage, entity.CurrentImageLayer.imgScaled);
	//////pOImage->Load(entity.strImageFileName.c_str());

	////pOImage->ConvertToARGB32Bits();
	////pBits	= (RGBQUAD*) pOImage->GetBits();

	////// Draw Background Image
	////pImage				= new CImageEx();
	////pImage->m_pBitmap	= new Bitmap(entity.CurrentImageLayer.Scaled_W, entity.CurrentImageLayer.Scaled_H, PixelFormat32bppPARGB);
	////pRGB				= (RGBQUAD*) pImage->GetBits();
	////for ( int i = 0; i < entity.CurrentImageLayer.Scaled_H; i++ )
	////{
	////	for ( int j = 0; j < entity.CurrentImageLayer.Scaled_W; j++, pRGB++, pBits++ )
	////	{
	////		pRGB->rgbBlue		= pBits->rgbBlue / 2 + 128;
	////		pRGB->rgbGreen		= pBits->rgbGreen / 2 + 128;
	////		pRGB->rgbRed		= pBits->rgbRed / 2 + 128;
	////		pRGB->rgbReserved	= pBits->rgbReserved;
	////	}
	////}
	////pImage->FreeBits();
	////pOImage->FreeBits();
	////pOImage->Unload();
	////delete	pOImage;

	////Graphics		graphics(pImage->m_pBitmap);
	////SolidBrush		myBrush(Color(0, 0, 0));
	////Pen				myPen(&myBrush, 2);
	////Font			myFont(L"Arial Narrow", 12, FontStyleBold);
	////wstring			strShowString;
	////char			szShowText[MAX_PATH];
	////PointF			point;

	////myPen.SetWidth(3);
	////for ( int i = 0; i < (int) Instance.LeafNodeInfo.size(); i++ )
	////{
	////	LeafID	= Instance.LeafNodeInfo[i].LeafNodeIndex;

	////	myBrush.SetColor(colors[LeafID % colors.size()]);
	////	myPen.SetColor(colors[LeafID % colors.size()]);

	////	point.X	= (float) Instance.LeafNodeInfo[i].node.x;
	////	point.Y	= (float) Instance.LeafNodeInfo[i].node.y;
	////	graphics.DrawEllipse(&myPen,   (int) (point.X - 3), (int) (point.Y - 3), (int) (2*3+1), (int) (2*3+1));
	////	graphics.FillEllipse(&myBrush, (int) (point.X - 3), (int) (point.Y - 3), (int) (2*3+1), (int) (2*3+1));
	////}

	////myPen.SetColor(Color(255, 0, 0));
	////myBrush.SetColor(Color(255, 0, 0));
	////sprintf_s(szShowText, MAX_PATH, "Score: %.3f", Instance.Score);
	////strShowString	= UTF82WChar( (const BYTE *)szShowText, (int) strlen(szShowText) );
	////point.X	= (float) (entity.CurrentImageLayer.Scaled_W - 8 * strlen(szShowText));
	////point.Y	= (float) (entity.CurrentImageLayer.Scaled_H - 20);
	////graphics.DrawString(strShowString.c_str(), (int) strShowString.length(), &myFont, point, &myBrush);

	////// Save Image
	////ret	= pImage->Save(strImageFileName.c_str());
	////delete	pImage;

	return	1;
}

int	CProposalTree::PrepareModel()
{
	int		ret;

	model.List_fIfNodeWork.assign(model.AndModels.size(), false);

	ret					= model.OrModels[model.Root].MakeMissInformation(model, model.OrModels[model.Root].Level);
	template_tree.Root	= model.Root;
	template_tree.AndNodes.resize(model.AndModels.size());
	template_tree.OrNodes.resize(model.OrModels.size());
	for ( int i = 0; i < (int) model.AndModels.size(); i++ )
	{
		template_tree.AndNodes[i].parseInfo	= false;
		template_tree.AndNodes[i].ModelID	= i;
		template_tree.AndNodes[i].Level 	= model.AndModels[i].Level;
		template_tree.AndNodes[i].NodeType	= model.AndModels[i].NodeType;
		template_tree.AndNodes[i].leafIndex	= model.AndModels[i].LeafIndex;
		template_tree.AndNodes[i].children	= model.AndModels[i].Children;
	}
	for ( int i = 0; i < (int) model.OrModels.size(); i++ )
	{
		template_tree.OrNodes[i].parseInfo	= false;
		template_tree.OrNodes[i].ModelID	= i;
		template_tree.OrNodes[i].Level 	= model.OrModels[i].Level;
		template_tree.OrNodes[i].children	= model.OrModels[i].Children;
	}

	return	1;
}

//int CProposalTree::ReadEntityFile(string strImageSetFileName, string strParseGroundPathName, vector<CHiBoostImageEntity> &ImageSet, string strFeaturePathName, int ParsedMode)
//{
//	ifstream		inImageSet(strImageSetFileName.c_str());
//	string			line;
//	int				Count;
//	int				ret;
//
//	inImageSet>>Count;
//
//	getline(inImageSet, line, '\n');
//	ImageSet.resize(Count);
//	ret = 0;
//	for ( int i = 0; i < Count; i++ )
//	{
//		getline(inImageSet, line, '\n');
//
//		ImageSet[i].SetImage(line, "", false);
//		// TODO
//		////if (ParsedMode == 1)
//		////	ImageSet[i].ReadGroundTruth(???)
//
//		////ret	= ImageSet[i].ReadImageFile(line, strFeaturePathName);
//		////if (ParsedMode == 1)
//		////	ret	= ImageSet[i].ReadParseGround(strParseGroundPathName);
//		////else if (ParsedMode == 2)
//		////	ret	= ImageSet[i].ReadParsedResult(strParseGroundPathName);
//
//		////ImageSet[i].EntityID	= i;
//
//		cout<<"\r"<<i+1<<" "<<Count<<setw(20)<<" ";
//	}
//	cout<<endl;
//
//	inImageSet.close();
//	return	1;
//}

int CProposalTree::RemakeTreeFromInst_NoEntity(InstanceTreeType &tree)
{
	for ( int j = 0; j < (int) tree.AndNodes.size(); j++ )
		tree.AndNodes[j].fNeedMakeInstTree = true;
	for ( int j = 0; j < (int) tree.OrNodes.size(); j++ )
		tree.OrNodes[j].fNeedMakeInstTree = true;

	int ret	= tree.OrNodes[tree.Root].RemakeInstTree_NoEntity(model, tree);

	for ( int j = 0; j < (int) tree.AndNodes.size(); j++ )
		tree.AndNodes[j].fNeedMakeInstTree = false;
	for ( int j = 0; j < (int) tree.OrNodes.size(); j++ )
		tree.OrNodes[j].fNeedMakeInstTree = false;

	return	1;
}

int CProposalTree::MakeTreeFromInst(
	InstanceTreeType &tree, CHiBoostImageEntity &entity, NodeInstanceType &instance,
	bool fComputeAppearanceScore, bool fFindNearestSampledPixels)
{
	vector<int>			NodeIndex;
	int					LeafCount, LeafID; // , NodeID;
	int					ret;

	tree			= template_tree;
	tree.Width		= entity.CurrentImageLayer.Scaled_W;
	tree.Height		= entity.CurrentImageLayer.Scaled_H;
	for ( int p = 0; p < (int) model.Rules.size(); p++ )
	{
		ret	= AddSearchCenterIndex(tree, model.Rules[p]);
	}

	for ( int j = 0; j < (int) tree.AndNodes.size(); j++ )
		tree.AndNodes[j].fNeedMakeInstTree = true;
	for ( int j = 0; j < (int) tree.OrNodes.size(); j++ )
		tree.OrNodes[j].fNeedMakeInstTree = true;

	NodeIndex.assign(model.LeafModels.size(), -1);
	LeafCount	= (int) instance.LeafNodeInfo.size();
	for ( int i = 0; i < LeafCount; i++ )
	{
		LeafID	= instance.LeafNodeInfo[i].LeafNodeIndex;

		NodeIndex[LeafID]	= i;
		for ( int j = 0; j < (int) tree.AndNodes.size(); j++ )
		{
			if (tree.AndNodes[j].leafIndex != LeafID)	continue;

			CLeafNodeModel		&CurrModel	= model.LeafModels[LeafID];
			BasicNodePairType	node_pair;
			NodeInstanceType	inst;

			CHiBoostImageLayer::CPixRef tpr;
			
			if (fFindNearestSampledPixels)
			{
				tpr = *entity.FindNearestSampledPixel_LayerCoordinate(
					//const CHiBoostImageLayer::CPixRef* pPixRef = entity.FindNearestSampledPixel_LayerCoordinate(
					instance.LeafNodeInfo[i].node.x, instance.LeafNodeInfo[i].node.y);
			}
			else
			{
				entity.CurrentImageLayer.BuildPixRef_LayerCoordinate(tpr, instance.LeafNodeInfo[i].node.x, instance.LeafNodeInfo[i].node.y);
				tpr.index = -1;
			}
			
			if (fComputeAppearanceScore)
				tree.AndNodes[j].BaseAppearanceScore = entity.GetAppearanceScore_LayerCoordinate(
					tpr.layer_fx, tpr.layer_fy, 1.0, j);
			else
				tree.AndNodes[j].BaseAppearanceScore = 0.0;
			////ret	= entity.FindNearestNodes(instance.LeafNodeInfo[i].node.x, instance.LeafNodeInfo[i].node.y, NodeID);
			////ret	= CurrModel.ConvertFeature(entity.nodes[NodeID].feature, tree.AndNodes[j].LeafFeature_);

			node_pair.LeafNodeIndex	= LeafID;	
			node_pair.node.x		= tpr.layer_fx; ////entity.nodes[NodeID].x;
			node_pair.node.y		= tpr.layer_fy; ////entity.nodes[NodeID].y;
			node_pair.node.ori		= 0.0; // tpr.gradient_orientation; ////entity.nodes[NodeID].ori;
			node_pair.Missing		= 0;											// ???
			node_pair.FixCount		= 1;

			inst.LeafNodeInfo.push_back(node_pair);
			inst.source.push_back(tpr.index);
			////inst.source.push_back(NodeID);
			inst.center.x			= node_pair.node.x;
			inst.center.y			= node_pair.node.y;
			
			inst.center.ori			= 0.0; // OriDiff(2 * CurrModel.ori, 2 * node_pair.node.ori) / 2;
			inst.center.scale		= 1.0;
			//inst.center.ori			= - OriDiff(2 * CurrModel.ori, 2 * node_pair.node.ori) / 2;
			//inst.center.scale		= -1.0;
			inst.center.OrIndex = -1;

			inst.Score	= 0.0;
			inst.ShapeScore = 0.0;
			inst.AppearanceScore = 0.0;
			inst.NodeBaseAppearanceScore = tree.AndNodes[j].BaseAppearanceScore;

			inst.AppearanceScore += model.AndModels[j].AppearanceWeight * inst.NodeBaseAppearanceScore;
			////for ( int k = 0; k < (int) CurrModel.Weights.size(); k++ )
			////{
			////	inst.AppearanceScore	+= CurrModel.Weights[k] * tree.AndNodes[j].LeafFeature_[k];
			////}

			inst.Score += inst.AppearanceScore;

			tree.AndNodes[j].instances.clear();
			tree.AndNodes[j].instances.push_back(inst);
			break;
		}
	}

	ret	= tree.OrNodes[tree.Root].MakeInstTree(model, entity, tree, fComputeAppearanceScore);

	for ( int j = 0; j < (int) tree.AndNodes.size(); j++ )
		tree.AndNodes[j].fNeedMakeInstTree = false;
	for ( int j = 0; j < (int) tree.OrNodes.size(); j++ )
		tree.OrNodes[j].fNeedMakeInstTree = false;

	return	1;
}

//int	CProposalTree::MakeTreeFromGround(vector<InstanceTreeType> &trees, vector<CHiBoostImageEntity> &entities)
//{	
//	int ret;
//	int EntityCount;
//	EntityCount	= (int) entities.size();
//	for ( int i = 0; i < EntityCount; i++ )
//		ret = MakeTreeFromGround(trees[i], entities[i]);
//	return	1;
//}

void CProposalTree::RefreshMRFScore(InstanceTreeType& DstInstTree)
{
	for ( int j = 0; j < (int)DstInstTree.OrNodes.size(); j++ )
		DstInstTree.OrNodes[j].fNeedRefreshMRFScore = true;
	for ( int j = 0; j < (int)DstInstTree.AndNodes.size(); j++ )
		DstInstTree.AndNodes[j].fNeedRefreshMRFScore = true;

	model.RuleStep = (int)model.Rules.size();
	DstInstTree.OrNodes[DstInstTree.Root].RefreshMRFScore(model, DstInstTree);

	for ( int j = 0; j < (int)DstInstTree.OrNodes.size(); j++ )
		DstInstTree.OrNodes[j].fNeedRefreshMRFScore = false;
	for ( int j = 0; j < (int)DstInstTree.AndNodes.size(); j++ )
		DstInstTree.AndNodes[j].fNeedRefreshMRFScore = false;
}

int	CProposalTree::MakeTreeFromGround(InstanceTreeType &tree, CHiBoostImageEntity &entity, bool fComputeAppearanceScore)
{
	NodeInstanceType	instance;
	int					LeafNodeCount;
	int					ret;

	instance.Score				= 0.0;
	instance.ShapeScore = instance.AppearanceScore = 0.0;
	instance.center.x			= 0.0;
	instance.center.y			= 0.0;
	instance.center.ori			= 0.0;
	instance.center.scale		= 1.0;
	instance.center.OrIndex = -1;
	instance.ChildCenters.clear();

	LeafNodeCount	= (int)entity.ParsedLeafInstanceList.Size; ////(int) entity.ParseNodes.size();
	//LeafNodeCount	= (int)entity.List_PtrParsedLeafInstance.Size; ////(int) entity.ParseNodes.size();

	instance.LeafNodeInfo.clear();
	instance.LeafNodeInfo.resize(LeafNodeCount);
	for ( int j = 0; j < LeafNodeCount; j++ )
	{
		//// My Convertion
		instance.LeafNodeInfo[j].node.x = entity.ParsedLeafInstanceList.pElement[j].layer_fx;
		instance.LeafNodeInfo[j].node.y = entity.ParsedLeafInstanceList.pElement[j].layer_fy;
		instance.LeafNodeInfo[j].node.ori = 0.0; // entity.ParsedLeafInstanceList.pElement[j].gradient_orientation;
		instance.LeafNodeInfo[j].LeafNodeIndex = j;
		instance.LeafNodeInfo[j].Missing = 0;
		instance.LeafNodeInfo[j].FixCount = 0;
		////instance.LeafNodeInfo[j]			= entity.ParseNodes[j];

		instance.LeafNodeInfo[j].FixCount = 1;
	}

	ret	= MakeTreeFromInst(tree, entity, instance, fComputeAppearanceScore, false);
	return	1;
}

//void CProposalTree::ComputeGroundTruthScore(
//	string strFN_PosImageSet, string strPN_PosFeature, string strPN_GroundTruth, int ParsedMode,
//	string strFN_GtScore
//	)
//{
//	int							ret;
//
//	vector<CHiBoostImageEntity>	PosTrainSet;
//	int							PosTrainCount;
//
//	int							i, j;
//	vector<InstanceTreeType>	GroundTrees;
//
//	ret	= ReadEntityFile(strFN_PosImageSet, strPN_GroundTruth, PosTrainSet, strPN_PosFeature, ParsedMode);
//	PosTrainCount	= (int)PosTrainSet.size();
//
//	//vector<double>		RealScores;
//	//double				Recall;
//	//int					Rank;
//	//int					ret;
//
//	ofstream outFile_GtScore(strFN_GtScore.c_str());
//
//	for ( int Step = 0; Step < (int) model.Rules.size(); ++Step )
//	{
//		outFile_GtScore<<endl<<"Step "<<Step+1<<" of "<<model.Rules.size()<<": "<<endl<<endl;
//
//		GroundTrees.assign(PosTrainSet.size(), template_tree);
//		model.RuleStep	= Step + 1;
//		ret				= MakeTreeFromGround(GroundTrees, PosTrainSet);
//
//		vector<double> ScoreList_SubTree;
//		ScoreList_SubTree.assign(model.AndModels.size(), 0.0);
//		vector<double> ScoreList_PerNode;
//		ScoreList_PerNode.assign(model.AndModels.size(), 0.0);
//
//		double ts;
//		for ( i = 0; i < GroundTrees.size(); ++i )
//		{
//			if ((int)PosTrainSet[i].ParsedLeafInstanceList.Size < 1) continue;
//
//			outFile_GtScore<<i; ////PosTrainSet[i].ImageID;
//
//			outFile_GtScore.precision(3);
//			GroundTrees[i].OrNodes[GroundTrees[i].Root].AnalyseScore(ScoreList_SubTree, ScoreList_PerNode, PosTrainSet[i], GroundTrees[i], 0);
//			ts = GroundTrees[i].OrNodes[GroundTrees[i].Root].instances[0].Score;
//			outFile_GtScore<<'\t'<<setw(8)<<fixed<<ts;
//
//			for ( j = 0; j < ScoreList_PerNode.size(); ++j )
//			{
//				ts = ScoreList_PerNode[j];
//				outFile_GtScore<<'\t'<<setw(8)<<fixed<<ts;
//			}
//			
//			outFile_GtScore<<endl;
//		}
//
//		//for ( int NodeID = 0; NodeID < (int) model.AndModels.size(); NodeID++ )
//		//{
//		//	RealScores.clear();
//		//	for ( int t = 0; t < (int) GroundTrees.size(); t++ )
//		//	{
//		//		if (GroundTrees[t].AndNodes[NodeID].instances.size() > 0)
//		//		{
//		//			RealScores.push_back(GroundTrees[t].AndNodes[NodeID].instances[0].Score);
//		//		}
//		//	}
//		//	sort(RealScores.begin(), RealScores.end(), greater<double>());
//
//		//	Recall	= g_Parameter.m_Recalls[model.AndModels[NodeID].Level];
//		//	Rank	= int(Recall * GroundTrees.size() + 0.5);
//		//	Rank	= __min((int) RealScores.size() - 1, Rank + 1);
//
//		//	model.AndModels[NodeID].Threshold[Step]	= RealScores[Rank];
//		//} 
//	}
//
//	outFile_GtScore.clear();
//	outFile_GtScore.close();
//}

double CProposalTree::SetAndNodeThreshold(CSimpleTypeArray<InstanceTreeType>& GroundTruthInstList)
{
	return SetAndNodeThreshold(GroundTruthInstList, g_Parameter.m_Recalls[model.AndModels[model.Root].Level]);
}

double CProposalTree::SetAndNodeThreshold(CSimpleTypeArray<InstanceTreeType>& GroundTruthInstList, double RootRecall)
{
	double ret = 0.0;

	int i_step = 0;

	int i_node;
	int i_gt;
	double TargetRecall;
	int TargetRank;
	double TargetThreshold;
	CSimpleTypeArray<double> ScoreList;

	for ( i_node = 0; i_node < (int)model.AndModels.size(); ++i_node )
	{
		ScoreList.Clear();

		for ( i_gt = 0; i_gt < (int)GroundTruthInstList.Size; ++i_gt )
		{
			if (GroundTruthInstList.pElement[i_gt].AndNodes[i_node].instances.size() > 0)
				ScoreList.PushBack(GroundTruthInstList.pElement[i_gt].AndNodes[i_node].instances[0].Score);
		}

		sort(ScoreList.Begin(), ScoreList.End(), greater<double>());

		if (ScoreList.Size < 1)
			TargetThreshold = 0.0;
		else
		{
			TargetRecall = g_Parameter.m_Recalls[model.AndModels[i_node].Level];

			double sr = ScoreList.pElement[0] - ScoreList.pElement[ScoreList.Size-1];
			if (sr < EPS) sr = EPS;
			sr *= EPS;

			if (i_node == model.Root)
				TargetRecall = RootRecall;
			TargetRank = int(TargetRecall * GroundTruthInstList.Size + 0.5);
			if (TargetRank < 0)
				TargetThreshold = ScoreList.pElement[0] + sr;
			else if (TargetRank + 1 >= (int)ScoreList.Size)
				TargetThreshold = ScoreList.pElement[(int)ScoreList.Size - 1] - sr;
			else
				TargetThreshold = (ScoreList.pElement[TargetRank] + ScoreList.pElement[TargetRank + 1]) * 0.50;
		}

		if (i_node == model.Root)
			ret = TargetThreshold;

		model.AndModels[i_node].Threshold[i_step] = TargetThreshold;
	}
	return ret;
}

//int	CProposalTree::SetAndNodeThreshold(vector<InstanceTreeType> &GroundTrees, vector<CHiBoostImageEntity> &TrainSet)
//{
//	//TODO
//
//	//vector<double>		RealScores;
//	//double				Recall;
//	//int					Rank;
//	//int					ret;
//
//	//for ( int Step = 0; Step < (int) model.Rules.size(); Step++ )
//	//{
//	//	GroundTrees.assign(TrainSet.size(), template_tree);
//	//	model.RuleStep	= Step + 1;
//	//	ret				= MakeTreeFromGround(GroundTrees, TrainSet);
//
//	//	for ( int NodeID = 0; NodeID < (int) model.AndModels.size(); NodeID++ )
//	//	{
//	//		RealScores.clear();
//	//		for ( int t = 0; t < (int) GroundTrees.size(); t++ )
//	//		{
//	//			if (GroundTrees[t].AndNodes[NodeID].instances.size() > 0)
//	//			{
//	//				RealScores.push_back(GroundTrees[t].AndNodes[NodeID].instances[0].Score);
//	//			}
//	//		}
//	//		sort(RealScores.begin(), RealScores.end(), greater<double>());
//
//	//		Recall	= g_Parameter.m_Recalls[model.AndModels[NodeID].Level];
//	//		Rank	= int(Recall * GroundTrees.size() + 0.5);
//	//		Rank	= __min((int) RealScores.size() - 1, Rank + 1);
//
//	//		model.AndModels[NodeID].Threshold[Step]	= RealScores[Rank];
//	//	} 
//	//}
//
//	return	1;
//}

void CProposalTree::DoDetection(CSimpleTypeArray<CMyTreeInstance>& DstMyTreeInstanceList, CHiBoostImageEntity& SrcEntity)
{
	CAndNodeModel& TTT = model.AndModels[model.Root];
	DoDetection(DstMyTreeInstanceList, SrcEntity, TTT.Threshold[0]);
}

void CProposalTree::DoDetection(CSimpleTypeArray<CMyTreeInstance>& DstMyTreeInstanceList, CHiBoostImageEntity& SrcEntity, double ScoreThreshold)
{
	CSimpleTypeArray<CMyTreeInstance> SrcMyTreeInstanceList;
	ParseEntity(SrcMyTreeInstanceList, SrcEntity, ScoreThreshold, "");
	CMyTreeInstance::DoDetectionNMS(DstMyTreeInstanceList, SrcMyTreeInstanceList);
}

bool CProposalTree::MakeMyTreeInstance(CMyTreeInstance& DstMyTreeInstance, InstanceTreeType& TreeInstance, int InstanceIndex, CHiBoostImageEntity& Entity)
{
	if (InstanceIndex<0 || InstanceIndex>=(int)TreeInstance.OrNodes[TreeInstance.Root].instances.size()) return false;

	int j;
	InstanceTreeType iiTree;
	CMyNodeInstance tMyNodeInstance;

	this->MakeTreeFromInst(iiTree, Entity, TreeInstance.OrNodes[TreeInstance.Root].instances[InstanceIndex], true, false);
	DstMyTreeInstance.Score = TreeInstance.OrNodes[TreeInstance.Root].instances[InstanceIndex].Score;
	DstMyTreeInstance.NodeInstanceList.Clear();
	CSimpleTypeArray<double> leaf_x_list;
	CSimpleTypeArray<double> leaf_y_list;
	leaf_x_list.Resize(model.LeafModels.size());
	leaf_y_list.Resize(model.LeafModels.size());
	for ( j = 0; j < (int)iiTree.AndNodes.size(); ++j )
	{
		if (iiTree.AndNodes[j].instances.size() < 1)
		{
			tMyNodeInstance.x = 0.0;
			tMyNodeInstance.y = 0.0;
			tMyNodeInstance.rot = 0.0;
			tMyNodeInstance.scale = 1.0;
			tMyNodeInstance.Score = 0.0;
			tMyNodeInstance.ShapeScore = 0.0;
			tMyNodeInstance.AppearanceScore = 0.0;
			tMyNodeInstance.BaseAppearanceScore = 0.0;
			tMyNodeInstance.fIsMissing = true;
		}
		else
		{
			NodeInstanceType tInst = iiTree.AndNodes[j].instances[0];
			tMyNodeInstance.x = tInst.center.x / Entity.CurrentImageLayer.ZoomConfig.xScale;
			tMyNodeInstance.y = tInst.center.y / Entity.CurrentImageLayer.ZoomConfig.yScale;
			tMyNodeInstance.rot = tInst.center.ori;
			tMyNodeInstance.scale = tInst.center.scale / Entity.CurrentImageLayer.BaseImageLayerScale;
			tMyNodeInstance.Score = tInst.Score;
			tMyNodeInstance.ShapeScore = tInst.ShapeScore;
			tMyNodeInstance.AppearanceScore = tInst.AppearanceScore;
			tMyNodeInstance.BaseAppearanceScore = tInst.NodeBaseAppearanceScore;
			tMyNodeInstance.fIsMissing = false;
		}

		if (model.AndModels[j].LeafIndex >= 0)
		{
			leaf_x_list.pElement[model.AndModels[j].LeafIndex] = tMyNodeInstance.x;
			leaf_y_list.pElement[model.AndModels[j].LeafIndex] = tMyNodeInstance.y;
		}
		DstMyTreeInstance.NodeInstanceList.PushBack(tMyNodeInstance);
	}
	DstMyTreeInstance.NodeInstanceBoxSet.InitLeafInstanceSet(leaf_x_list, leaf_y_list);
	DstMyTreeInstance.DetectionBox = DstMyTreeInstance.NodeInstanceBoxSet.All_BoundingBox;

	return true;
}

void CProposalTree::MakeMyNodeInstanceList(
	CSimpleTypeArray<CMyNodeInstance>& DstMyNodeInstanceList, bool fAppendMode, bool fUseFullInst,
	int NodeIndex, InstanceTreeType& TreeInstance, CHiBoostImageEntity& Entity)
{
	if (!fAppendMode) DstMyNodeInstanceList.Clear();
	if (NodeIndex<0 || NodeIndex>=(int)model.AndModels.size()) return;
	CMyNodeInstance tMyNodeInstance;
	vector<NodeInstanceType>& vni = (fUseFullInst ? 
		TreeInstance.AndNodes[NodeIndex].fullInst : TreeInstance.AndNodes[NodeIndex].instances);
	double CT = model.AndModels[NodeIndex].Threshold[0];

	//for ( int i = 0; i < Entity.CurrentImageLayer.PixelAmount; ++i )
	//{
	//	CHiBoostImageLayer::CPixRef& tpr = Entity.CurrentImageLayer.PixRefList.pElement[i];
	//	tMyNodeInstance.x = tpr.original_fx;
	//	tMyNodeInstance.y = tpr.original_fy;
	//	tMyNodeInstance.scale = 1.0 / Entity.CurrentImageLayer.BaseImageLayerScale;
	//	tMyNodeInstance.Score = 0.0;
	//	tMyNodeInstance.ShapeScore = 0.0;
	//	tMyNodeInstance.AppearanceScore = 0.0;
	//	tMyNodeInstance.BaseAppearanceScore = 0.0;
	//	tMyNodeInstance.fIsMissing = false;
	//	DstMyNodeInstanceList.PushBack(tMyNodeInstance);
	//}

	for ( int i = 0; i < (int)vni.size(); ++i )
	{
		NodeInstanceType tInst = vni[i];
		if (tInst.Score < CT) continue;
		tMyNodeInstance.x = tInst.center.x / Entity.CurrentImageLayer.ZoomConfig.xScale;
		tMyNodeInstance.y = tInst.center.y / Entity.CurrentImageLayer.ZoomConfig.yScale;
		tMyNodeInstance.rot = tInst.center.ori;
		tMyNodeInstance.scale = tInst.center.scale / Entity.CurrentImageLayer.BaseImageLayerScale;
		tMyNodeInstance.Score = tInst.Score;
		tMyNodeInstance.ShapeScore = tInst.ShapeScore;
		tMyNodeInstance.AppearanceScore = tInst.AppearanceScore;
		tMyNodeInstance.BaseAppearanceScore = tInst.NodeBaseAppearanceScore;
		tMyNodeInstance.fIsMissing = false;
		DstMyNodeInstanceList.PushBack(tMyNodeInstance);
	}

}

void CProposalTree::MakeCanDetList(
	CSimpleTypeArray<CCandidateDetection>& DstCanDetList, bool fAppendMode, bool fUseFullInst,
	int NodeIndex, InstanceTreeType& TreeInstance, CHiBoostImageEntity& Entity)
{
	if (!fAppendMode) DstCanDetList.Clear();
	if (NodeIndex<0 || NodeIndex>=(int)model.AndModels.size()) return;
	CCandidateDetection tCanDet;
	vector<NodeInstanceType>& vni = (fUseFullInst ? 
		TreeInstance.AndNodes[NodeIndex].fullInst : TreeInstance.AndNodes[NodeIndex].instances);
	double CT = model.AndModels[NodeIndex].Threshold[0];
	for ( int i = 0; i < (int)vni.size(); ++i )
	{
		NodeInstanceType tInst = vni[i];
		if (tInst.Score < CT) continue;
		tCanDet.ipp.InitNew(
			tInst.center.x / Entity.CurrentImageLayer.ZoomConfig.xScale,
			tInst.center.y / Entity.CurrentImageLayer.ZoomConfig.yScale,
			Entity.CurrentImageLayer.BaseImageLayerScale / tInst.center.scale,
			Entity.CurrentImageLayer.BaseImageLayerScale / tInst.center.scale);
		tCanDet.Confidence = tInst.Score;
		tCanDet.Tag = i;
		DstCanDetList.PushBack(tCanDet);
	}
}

void CProposalTree::ParseEntity(
	CSimpleTypeArray<CMyTreeInstance>& DstMyTreeInstanceList,
	CHiBoostImageEntity& entity,
	double ScoreThreshold,
	string strPN_ParseLog)
{
	InstanceTreeType iTree;

	CExternalTools::ConsoleTools::MakeDirectory(strPN_ParseLog);

	int i_layer, i_inst;

	CMyTreeInstance tMyTreeInstance;

	for ( i_layer = 0; ; ++i_layer )
	{
		if (!entity.SetCurrentImageLayer(i_layer)) break;
		ParseEntityCurrentLayer(iTree, entity, strPN_ParseLog);

		for ( i_inst = 0; i_inst < (int)iTree.OrNodes[iTree.Root].instances.size(); ++i_inst )
		{
			MakeMyTreeInstance(tMyTreeInstance, iTree, i_inst, entity);
			if (tMyTreeInstance.Score > ScoreThreshold)
				DstMyTreeInstanceList.PushBack(tMyTreeInstance);
		}
	}
}

void CProposalTree::LearnModelParamaters(
	const CHiBoostGroundTruthList& GT_List,
	string strPN_BaseParseLog,
	string strPN_TrainedModel,
	string strPN_LoadInstance,
	const CSimpleTypeArray<string>& List_strFN_SrcImage_Neg,
	const CSimpleTypeArray<string>& List_strSrcImageHashName_Neg)
{
	char strTemp[10001];

	CImg<int> imgSrc;
	InstanceTreeType iTree;
	CHiBoostImageEntity iEntity;
	int i_update, j_update;
	int i_iteration;
	int i_image;
	int i_layer;
	int i_inst;
	int i_gt;

	CExternalTools::ConsoleTools::MakeDirectory(strPN_BaseParseLog, true);
	CExternalTools::ConsoleTools::MakeDirectory(strPN_TrainedModel, true);
	CExternalTools::ConsoleTools::MakeDirectory(strPN_TrainedModel + "AM\\", true);
	CExternalTools::ConsoleTools::MakeDirectory(strPN_TrainedModel + "SM\\", true);

	ofstream outLog("Learning.log");

	int Amount_SrcImage_Pos = GT_List.Amount_SrcImage_Pos;
	int Amount_SrcImage_Neg = (int)List_strFN_SrcImage_Neg.Size;
	CSimpleTypeArray<string*> List_Ptr_strFN_ImageForParse;
	CSimpleTypeArray<string*> List_Ptr_strImageHashNameForParse;
	CSimpleTypeArray<bool> List_fFlipped;
	List_Ptr_strFN_ImageForParse.Clear();
	List_Ptr_strImageHashNameForParse.Clear();
	List_fFlipped.Clear();
	for ( i_image = 0; i_image < Amount_SrcImage_Pos; ++i_image )
	{
		List_Ptr_strFN_ImageForParse.PushBack(GT_List.List_strFN_SrcImage_Pos.pElement + i_image);
		List_Ptr_strImageHashNameForParse.PushBack(GT_List.List_strSrcImageHashName.pElement + i_image);
		List_fFlipped.PushBack(false);
		//List_Ptr_strFN_ImageForParse.PushBack(GT_List.List_strFN_SrcImage_Pos.pElement + i_image);
		//List_Ptr_strImageHashNameForParse.PushBack(GT_List.List_strSrcImageHashName.pElement + i_image);
		//List_fFlipped.PushBack(true);
	}
	for ( i_image = 0; i_image < Amount_SrcImage_Neg; ++i_image )
	{
		List_Ptr_strFN_ImageForParse.PushBack(List_strFN_SrcImage_Neg.pElement + i_image);
		List_Ptr_strImageHashNameForParse.PushBack(List_strSrcImageHashName_Neg.pElement + i_image);
		List_fFlipped.PushBack(false);
	}
	int Amount_ImageForParse = (int)List_Ptr_strFN_ImageForParse.Size;
	string** qqFN_ImageForParse;
	string** qqImageHashName;
	bool* q_fFlipped;

	int Amount_GroundTruth = GT_List.Amount_GroundTruth;
	CSimpleTypeArray<InstanceTreeType> GroundTruthInstTreeList;
	const double* qBaseGroundTruthScale = GT_List.BaseImageLayerScaleList.pElement;
	ParseGroundTruthList(GroundTruthInstTreeList, GT_List, true, strPN_LoadInstance, "", "");

	ModelTreeType UpdateModel;
	ModelTreeType AveModel;
	ModelTreeType CurModel;
	double Score_Image;
	double Score_GT;

	CTimer timParser;
	
	i_update = 0;
	this->InitAverageModel(AveModel);

	// Refresh Ground Truth List & Parsing Threshold List
	for ( i_gt = 0; i_gt < Amount_GroundTruth; ++i_gt )
	{
		InstanceTreeType& CurrentInstGT = GroundTruthInstTreeList.pElement[i_gt];
		this->RefreshMRFScore(CurrentInstGT);
	}
	SetAndNodeThreshold(GroundTruthInstTreeList);

	for ( i_iteration = 0; i_iteration < g_Parameter.Amount_TrainingIteration; ++i_iteration )
	{
		qqFN_ImageForParse = List_Ptr_strFN_ImageForParse.pElement;
		qqImageHashName = List_Ptr_strImageHashNameForParse.pElement;
		q_fFlipped = List_fFlipped.pElement;
		for ( i_image = 0; i_image < Amount_ImageForParse; ++i_image, ++qqFN_ImageForParse, ++qqImageHashName, ++q_fFlipped )
		{
			CExternalTools::myLoadImage(**qqFN_ImageForParse, imgSrc);
			iEntity.SetImage(imgSrc, **qqImageHashName, *q_fFlipped);
			imgSrc = iEntity.imgSource;

			timParser.Reset();
			for ( i_layer = 0; ; ++i_layer )
			{
				if (!iEntity.SetCurrentImageLayer(i_layer)) break;

				timParser.Start();
				string strPN_CurrentParseLog;
				sprintf_s(strTemp, "%s%04d.%04d\\", strPN_BaseParseLog.c_str(), i_image, i_layer);
				strPN_CurrentParseLog = strTemp;
				CExternalTools::ConsoleTools::ClearCurrentLine();
				CExternalTools::ConsoleTools::MakeDirectory(strPN_CurrentParseLog, true);
				ParseEntityCurrentLayer(iTree, iEntity, strPN_CurrentParseLog);
				timParser.Stop();

				++i_update;
				j_update = 0;
				UpdateModel = model;
				double UpdatingWeight = 1.0 / g_Parameter.Amount_InstanceForUpdating; // 1.0 / 32.0 / g_Parameter.Amount_InstanceForUpdating;
				for ( i_inst = 0; i_inst < g_Parameter.Amount_InstanceForUpdating; ++i_inst )
				{
					if (i_inst >= (int)iTree.OrNodes[model.Root].instances.size()) break;

					NodeInstanceType& CurrentRootNodeInstance = iTree.OrNodes[model.Root].instances[i_inst];

					//sprintf_s(strTemp,"Parse.%04d.%04d.%04d.jpg", i_image, i_layer, i_inst);
					//DrawInstance(iEntity, CurrentRootNodeInstance, strTemp);

					//continue;

					Score_Image = CurrentRootNodeInstance.Score;

					for ( i_gt = 0; i_gt < Amount_GroundTruth; ++i_gt )
					{
						InstanceTreeType& CurrentInstGT = GroundTruthInstTreeList.pElement[i_gt];

						Score_GT = CurrentInstGT.OrNodes[model.Root].instances[0].Score;
						if (Score_GT > Score_Image) continue;

						++j_update;
						iTree.OrNodes[model.Root].UpdateParameters(model, UpdateModel, iEntity, iTree, CurrentInstGT, i_inst, UpdatingWeight);
					}
				}	// end i_inst

				//continue;

				// Correct Parameters
				for ( int i = 0; i < (int) UpdateModel.AndModels.size(); i++ )
				{
					UpdateModel.AndModels[i].AppearanceWeight = __max(0.1, UpdateModel.AndModels[i].AppearanceWeight);

					if (UpdateModel.AndModels[i].NodeType == 0) continue;
					for ( int j = 0; j < (int) UpdateModel.AndModels[i].triplets.size(); j++ )
					{
						UpdateModel.AndModels[i].triplets[j].gamma	= __max(0.1, UpdateModel.AndModels[i].triplets[j].gamma);
					}
				}
				model = UpdateModel;

				CurModel = model;
				this->MakeAverageModel(AveModel, i_update);
				if (i_update % 100 == 0)
				{
					// Refresh Ground Truth List & Parsing Threshold List
					for ( i_gt = 0; i_gt < Amount_GroundTruth; ++i_gt )
					{
						InstanceTreeType& CurrentInstGT = GroundTruthInstTreeList.pElement[i_gt];
						this->RefreshMRFScore(CurrentInstGT);
					}
					SetAndNodeThreshold(GroundTruthInstTreeList);

					sprintf_s(strTemp, "%sAM\\AM.%05d.%02d.%04d.%02d.txt", strPN_TrainedModel.c_str(), i_update, i_iteration, i_image, i_layer);
					this->SaveAndOrTreeModel(strTemp);
				}
				model = CurModel;

				// Refresh Ground Truth List & Parsing Threshold List
				for ( i_gt = 0; i_gt < Amount_GroundTruth; ++i_gt )
				{
					InstanceTreeType& CurrentInstGT = GroundTruthInstTreeList.pElement[i_gt];
					this->RefreshMRFScore(CurrentInstGT);
				}
				SetAndNodeThreshold(GroundTruthInstTreeList);

				sprintf_s(strTemp, "%sSM\\SM.%05d.%02d.%04d.%02d.txt", strPN_TrainedModel.c_str(), i_update, i_iteration, i_image, i_layer);
				this->SaveAndOrTreeModel(strTemp);

				//exit(0);

				sprintf_s(strTemp, "Itr/Img/Lyr %02d/%04d/%02d, [%4d,%4d]: %3d instances, %d updates;",
					i_iteration, i_image, i_layer, iTree.Width, iTree.Height, (int)iTree.OrNodes[model.Root].instances.size(),
					j_update);
				CExternalTools::ConsoleTools::ClearCurrentLine();
				cout<<strTemp;
				outLog<<strTemp<<endl;
			}	// end i_layer
			
			sprintf_s(strTemp, "Parsed iteration %02d image %04d, taking %s;",
				i_iteration, i_image,
				CExternalTools::GetTimeText(timParser.GetCumulativeTime()));
			CExternalTools::ConsoleTools::ClearCurrentLine();
			cout<<strTemp<<endl;
			outLog<<strTemp<<endl;
		}	// end i_image
	}	// end i_iteration

	outLog.clear();
	outLog.close();
}

int	CProposalTree::LearnModelParamaters(
	string strPosTrainFileName, string strPosFeaturePathName, string strPosParseGroundPathName,
	string strNegTrainFileName, string strNegFeaturePathName, string strTrainParsePathName
	)
{
	////vector<CHiBoostImageEntity>				PosTrainSet;
	////vector<InstanceTreeType>	PosGroundTrees;
	////InstanceTreeType			Postree;
	////int							PosTrainCount;

	////vector<CHiBoostImageEntity>				NegTrainSet;
	////InstanceTreeType			Negtree;
	////int							NegTrainCount;

	//////vector<CHiBoostImageEntity>				TrainSet;
	//////vector<InstanceTreeType>	GroundTrees;
	////InstanceTreeType			tree;
	////ModelTreeType				UpdateModel, AveModel, CurModel;
	////char						fname[MAX_PATH], command[MAX_PATH];
	////CTimer						timer;
	////double						TimeCost;
	//////int							TrainCount;
	////int							Step;
	////int							ret;

	////// Entities
	////ret	= ReadEntityFile(strPosTrainFileName, strPosParseGroundPathName, PosTrainSet, strPosFeaturePathName, 1);
	////ret	= ReadEntityFile(strNegTrainFileName, ":", NegTrainSet, strNegFeaturePathName, 0);

	////PosTrainCount	= (int)PosTrainSet.size();
	////NegTrainCount	= (int)NegTrainSet.size();

	////// Average Model
	////ret	= InitAverageModel(AveModel);

	////// Set Thresholds
	////ret	= SetAndNodeThreshold(PosGroundTrees, PosTrainSet);

	////char strTemp[MAX_PATH+101];
	////sprintf_s(strTemp, "md LearnModels > nul"); system(strTemp);

	////Step	= 0;
	////for ( int Times = 0; Times < 10; Times++ )
	////{
	////	for ( int tn = 0; tn < NegTrainCount; tn++ )
	////	{
	////		Step++;
	////		sprintf_s(command, MAX_PATH, "rmdir /s /q %s\\%04d >:null", strTrainParsePathName.c_str(), tn+1);	system(command);
	////		sprintf_s(command, MAX_PATH, "mkdir %s\\%04d >:null", strTrainParsePathName.c_str(), tn+1);			system(command);

	////		tree			= template_tree;

	////		tree.Width		= NegTrainSet[tn].W;
	////		tree.Height		= NegTrainSet[tn].H;

	////		// Inference _Neg
	////		timer.Reset();
	////		timer.Start();
	////		for ( int p = 0; p < (int) model.Rules.size(); p++ )
	////		{
	////			model.RuleStep	= p + 1;
	////			ret	= AddSearchCenterIndex(tree, model.Rules[p]);

	////			ret	= tree.OrNodes[root].BottomUpSearch(model, NegTrainSet[tn], tree, strTrainParsePathName.c_str());
	////			ret	= tree.OrNodes[root].MakeSearchConstrain(model, tree, NegTrainSet[tn]);
	////		}
	////		timer.Stop();
	////		TimeCost	= timer.GetElapsedTime();

	////		if (tree.OrNodes[root].instances.size() < 1) continue;

	////		// Compute Score _GroundTruth
	////		PosGroundTrees.assign(PosTrainCount, template_tree);
	////		model.RuleStep	= (int) model.Rules.size();
	////		ret				= MakeTreeFromGround(PosGroundTrees, PosTrainSet);

	////		double ns = tree.OrNodes[root].instances[0].Score;
	////		int modification_amount = 0;

	////		cout.precision(2);

	////		cout<<"Image "<<tn+1<<" / "<<NegTrainCount<<": ";

	////		cout<<setw(12)<<fixed<<ns;

	////		UpdateModel	= model;

	////		for ( int tp = 0; tp < PosTrainCount; tp++ )
	////		{
	////			double ps = PosGroundTrees[tp].OrNodes[PosGroundTrees[tp].Root].instances[0].Score;

	////			//cout<<setw(10)<<fixed<<TimeCost<<"s";
	////			if (ns > ps)
	////			{
	////				++modification_amount;

	////				//Update

	////				ret	= tree.OrNodes[root].UpdateParameters(model, UpdateModel, NegTrainSet[tn], tree, PosGroundTrees[tp], 0);

	////				// Correct Parameters
	////				for ( int i = 0; i < (int) UpdateModel.AndModels.size(); i++ )
	////				{
	////					if (UpdateModel.AndModels[i].NodeType == 0)
	////					{
	////						continue;
	////					}

	////					for ( int j = 0; j < (int) UpdateModel.AndModels[i].triplets.size(); j++ )
	////					{
	////						UpdateModel.AndModels[i].triplets[j].gamma	= __max(0.1, UpdateModel.AndModels[i].triplets[j].gamma);
	////					}
	////				}

	////				for ( int i = 0; i < (int) UpdateModel.Rules.size(); i++ )
	////				{
	////					UpdateModel.Rules[i].ScaleWeight	= __max(UpdateModel.Rules[i].ScaleWeight, 0);
	////					UpdateModel.Rules[i].RotWeight		= __max(UpdateModel.Rules[i].RotWeight, 0);
	////				}
	////			}
	////		}
	////		model	= UpdateModel;

	////		cout<<" "<<modification_amount<<endl;

	////		ret	= SetAndNodeThreshold(PosGroundTrees, PosTrainSet);
	////		if (Step % 50 == 0)
	////		{
	////			sprintf_s(fname, "LearnModels\\SM%04d.txt", Step);
	////			ret	= SaveAndOrTreeModel(fname);
	////		}

	////		CurModel	= model;
	////		ret			= MakeAverageModel(AveModel, Step);
	////		ret			= SetAndNodeThreshold(PosGroundTrees, PosTrainSet);
	////		if (Step % 50 == 0)
	////		{
	////			sprintf_s(fname, "LearnModels\\AM%04d.txt", Step);
	////			ret	= SaveAndOrTreeModel(fname);
	////		}
	////		model		= CurModel;
	////	}
	////}

	return	1;
}

int CProposalTree::InitAverageModel(ModelTreeType &AveModel)
{
	AveModel	= model;

	for ( int i = 0; i < (int) AveModel.LeafModels.size(); i++ )
	{
		////for ( int j = 0; j < (int) AveModel.LeafModels[i].Weights.size(); j++ )
		////{
		////	AveModel.LeafModels[i].Weights[j]	= 0;
		////}
	}

	for ( int i = 0; i < (int) AveModel.AndModels.size(); i++ )
	{
		AveModel.AndModels[i].AppearanceWeight = 0.0;

		if (AveModel.AndModels[i].NodeType == 0)
			continue;
		for ( int j = 0; j < (int) AveModel.AndModels[i].triplets.size(); j++ )
		{
			AveModel.AndModels[i].triplets[j].gamma	= 0;
		}
	}

	for ( int i = 0; i < (int) model.Rules.size(); i++ )
	{
		AveModel.Rules[i].ScaleWeight	= 0;
		AveModel.Rules[i].RotWeight		= 0;
	}
 

	return	1;
}

int CProposalTree::MakeAverageModel(ModelTreeType &AveModel, int Count)
{
	for ( int i = 0; i < (int) AveModel.LeafModels.size(); i++ )
	{
		//for ( int j = 0; j < (int) AveModel.LeafModels[i].Weights.size(); j++ )
		//{
		//	AveModel.LeafModels[i].Weights[j]	+= model.LeafModels[i].Weights[j];
		//	model.LeafModels[i].Weights[j]		= AveModel.LeafModels[i].Weights[j] / Count;
		//}
	}

	for ( int i = 0; i < (int) AveModel.AndModels.size(); i++ )
	{
		AveModel.AndModels[i].AppearanceWeight += model.AndModels[i].AppearanceWeight;
		model.AndModels[i].AppearanceWeight = AveModel.AndModels[i].AppearanceWeight / Count;

		if (AveModel.AndModels[i].NodeType == 0) continue;

		for ( int j = 0; j < (int) AveModel.AndModels[i].triplets.size(); j++ )
		{
			AveModel.AndModels[i].triplets[j].gamma	+= model.AndModels[i].triplets[j].gamma;
			model.AndModels[i].triplets[j].gamma	= AveModel.AndModels[i].triplets[j].gamma / Count;
		}
	}

	for ( int i = 0; i < (int) model.Rules.size(); i++ )
	{
		AveModel.Rules[i].ScaleWeight	+= model.Rules[i].ScaleWeight;
		model.Rules[i].ScaleWeight		= AveModel.Rules[i].ScaleWeight / Count;
		AveModel.Rules[i].RotWeight		+= model.Rules[i].RotWeight;
		model.Rules[i].RotWeight		= AveModel.Rules[i].RotWeight / Count;
	}

	return	1;
}

//void CProposalTree::ParseImage(
//	string strFN_Image, bool fIsFlipped, string strFN_GroundTruth,
//	string strFN_Log, string strPN_FinalResult, string strPN_Boundary, string strPN_ParseImage
//	)
//{
//	ofstream			outLog(strFN_Log.c_str());
//
//	char				command[MAX_PATH], fname[MAX_PATH];
//
//	//sprintf_s(command, MAX_PATH, "rmdir /s /q %s >:null", strPN_ParseImage.c_str());	system(command);
//	sprintf_s(command, MAX_PATH, "mkdir %s >:null", strPN_ParseImage.c_str());			system(command);
//	//sprintf_s(command, MAX_PATH, "rmdir /s /q %s >:null", strPN_FinalResult.c_str());	system(command);
//	sprintf_s(command, MAX_PATH, "mkdir %s >:null", strPN_FinalResult.c_str());			system(command);
//	//sprintf_s(command, MAX_PATH, "rmdir /s /q %s >:null", strPN_Boundary.c_str());		system(command);
//	sprintf_s(command, MAX_PATH, "mkdir %s >:null", strPN_Boundary.c_str());			system(command);
//
//	//TODO
//
//	outLog.clear();
//	outLog.close();
//}

void CProposalTree::ParseGroundTruthList(
	CSimpleTypeArray<InstanceTreeType>& DstGroundTruthInstTreeList,
	const CHiBoostGroundTruthList& GT_List,
	bool fComputeAppearanceScore,
	string strPN_LoadInstance, string strPN_SaveInstance, string strPN_DrawInstance
	)
{
	char strTemp[10001];

	if (strPN_SaveInstance != "")
	{
		CExternalTools::ConsoleTools::MakeDirectory(strPN_SaveInstance, true);
	}

	if (strPN_DrawInstance != "")
	{
		CExternalTools::ConsoleTools::MakeDirectory(strPN_DrawInstance, true);
	}

	int i_gt;
	CImg<int> imgSrc;
	CHiBoostGroundTruth tGT;
	CHiBoostImageEntity iEntity;

	DstGroundTruthInstTreeList.DeepClear();
	DstGroundTruthInstTreeList.Resize(GT_List.Amount_GroundTruth);
	for ( i_gt = 0; i_gt < GT_List.Amount_GroundTruth; ++i_gt )
	{
		InstanceTreeType& iTree = DstGroundTruthInstTreeList.pElement[i_gt];

		bool f_successfully_loaded = false;
		if (strPN_LoadInstance != "")
		{
			sprintf_s(strTemp, "%s%04d.txt", strPN_LoadInstance.c_str(), i_gt);

			//GT_List.GetGroundTruth(tGT, imgSrc, i_gt, 0);
			//iEntity.SetImage(imgSrc);
			//iEntity.ReadParsedLeafInstances(&tGT);
			//this->ParseEntityGroundTruth(iTree, iEntity, false);
			//ofstream outFile(strTemp);
			//iTree.OutputToStream(outFile);
			//outFile.clear();
			//outFile.close();

			ifstream inFile(strTemp);
			f_successfully_loaded = iTree.InputFromStream(inFile);
			inFile.clear();
			inFile.close();
		}

		if (!f_successfully_loaded || strPN_DrawInstance != "")
		{
			GT_List.GetGroundTruth(tGT, imgSrc, i_gt, 0.333);
			iEntity.SetImage(imgSrc, "", false);
			iEntity.ReadParsedLeafInstances(&tGT);
		}

		if (!f_successfully_loaded)
		{
			this->ParseEntityGroundTruth(iTree, iEntity, fComputeAppearanceScore);
		}

		if (strPN_SaveInstance != "")
		{
			sprintf_s(strTemp, "%s%04d.txt", strPN_SaveInstance.c_str(), i_gt);
			ofstream outFile(strTemp);
			iTree.OutputToStream(outFile);
			outFile.clear();
			outFile.close();
		}

		if (strPN_DrawInstance != "")
		{
			//GT_List.GetGroundTruth(tGT, imgSrc, i_gt, 0.5);
			//iEntity.SetImage(imgSrc, "", false);
			//iEntity.ReadParsedLeafInstances(&tGT);
			sprintf_s(strTemp, "%s%04d.jpg", strPN_DrawInstance.c_str(), i_gt);
			this->DrawInstance(iEntity, iTree.OrNodes[iTree.Root].instances[0], strTemp);
		}

		CExternalTools::ConsoleTools::ClearCurrentLine();
		sprintf_s(strTemp, "Parsed Ground Truth %d/%d...", i_gt+1, GT_List.Amount_GroundTruth);
		cout<<strTemp;
	}
	CExternalTools::ConsoleTools::ClearCurrentLine();
}

void CProposalTree::ParseEntityGroundTruth(
	InstanceTreeType& DstInstTree,
	CHiBoostImageEntity& entity,
	bool fComputeAppearanceScore)
{
	DstInstTree = template_tree;
	DstInstTree.Width = entity.CurrentImageLayer.Scaled_W;
	DstInstTree.Height = entity.CurrentImageLayer.Scaled_H;

	model.RuleStep = (int)model.Rules.size();
	MakeTreeFromGround(DstInstTree, entity, fComputeAppearanceScore);
}

void CProposalTree::ParseEntityCurrentLayer(
	InstanceTreeType& DstInstTree,
	CHiBoostImageEntity& entity,
	string strPN_ParseLog)
{
	int ret;

	DstInstTree = template_tree;
	DstInstTree.Width = entity.CurrentImageLayer.Scaled_W;
	DstInstTree.Height = entity.CurrentImageLayer.Scaled_H;

	entity.ClearAppearanceScoreCountLog_CurrentLayer();
	//entity.timAppearanceComputing_CurrentLayer.Reset();

	int layer_loaded = 0 - entity.pIPPFE->LayersUsedCount;

	for ( int i_rule = 0; i_rule < (int) model.Rules.size(); ++i_rule )
	{
		model.RuleStep	= i_rule + 1;
		ret	= AddSearchCenterIndex(DstInstTree, model.Rules[i_rule]);
		ret	= DstInstTree.OrNodes[model.Root].BottomUpSearch(model, entity, DstInstTree, strPN_ParseLog.c_str());
		ret	= DstInstTree.OrNodes[model.Root].MakeSearchConstrain(model, DstInstTree, entity);
	}

	layer_loaded += entity.pIPPFE->LayersUsedCount;
	//double appearance_cost = entity.timAppearanceComputing_CurrentLayer.GetCumulativeTime();
	//CExternalTools::ConsoleTools::ClearCurrentLine();
	//cout<<entity.Amount_CalculationMade_CurrentLayer<<" "<<entity.Amount_QueryReceived_CurrentLayer<<" ";
	//cout<<layer_loaded<<" "<<CExternalTools::GetTimeText(appearance_cost)<<endl;
}

////int	CProposalTree::ParseImageSet(
////	string strImageSetFileName, string strFeaturePathName, string strParseGroundPathName,
////	string strFN_Log, string strPN_FinalResult, string strPN_Boundary, string strPN_ParseImage
////	)
////{
////	ofstream			outLog(strFN_Log.c_str());
////	ifstream			inImageSet(strImageSetFileName.c_str());
////	char				command[MAX_PATH], fname[MAX_PATH];
////	string				line;
////	int					ImageCount;
////	int					ret;
////	int					t;
////	char				strTemp[10000];
////
////	inImageSet>>ImageCount;
////	getline(inImageSet, line, '\n');
////
////	sprintf_s(command, MAX_PATH, "rmdir /s /q %s >:null", strPN_ParseImage.c_str());	system(command);
////	sprintf_s(command, MAX_PATH, "mkdir %s >:null", strPN_ParseImage.c_str());			system(command);
////	sprintf_s(command, MAX_PATH, "rmdir /s /q %s >:null", strPN_FinalResult.c_str());	system(command);
////	sprintf_s(command, MAX_PATH, "mkdir %s >:null", strPN_FinalResult.c_str());			system(command);
////	sprintf_s(command, MAX_PATH, "rmdir /s /q %s >:null", strPN_Boundary.c_str());		system(command);
////	sprintf_s(command, MAX_PATH, "mkdir %s >:null", strPN_Boundary.c_str());			system(command);
////	//ret	= ParseStat.InitAverageDist();
////
////	InstanceTreeType gt_tree;
////	vector<double> PerNodeRecall;
////
////	double ape = 0.0;
////
////	for ( t = 0; t < ImageCount; t++ )
////	{
////		InstanceTreeType	tree;
////		CHiBoostImageEntity				entity;
////		double				TimeCost, AvePos;
////		CTimer				timer;
////
////		getline(inImageSet, line, '\n');
////		ret				= entity.ReadImageFile(line, strFeaturePathName);
////		if (strParseGroundPathName != "")
////		{
////			ret = entity.ReadParseGround(strParseGroundPathName);
////			ret = MakeTreeFromGround(gt_tree, entity);
////
////			if (t == 0)
////				PerNodeRecall.assign(gt_tree.AndNodes.size(), 0.0);
////		}
////		entity.EntityID	= t;
////
////		//if (t != 5) continue;
////
////		tree			= template_tree;
////		tree.Width		= entity.W;
////		tree.Height		= entity.H;
////
////		sprintf_s(command, MAX_PATH, "rmdir /s /q %s\\%04d >:null", strPN_ParseImage.c_str(), t+1);		system(command);
////		sprintf_s(command, MAX_PATH, "mkdir %s\\%04d >:null", strPN_ParseImage.c_str(), t+1);			system(command);
////
////		timer.Reset();
////		timer.Start();
////		for ( int p = 0; p < (int) model.Rules.size(); p++ )
////		{
////			model.RuleStep	= p + 1;
////			ret	= AddSearchCenterIndex(tree, model.Rules[p]);
////			ret	= tree.OrNodes[root].BottomUpSearch(model, entity, tree, strPN_ParseImage.c_str());
////			ret	= tree.OrNodes[root].MakeSearchConstrain(model, tree, entity);
////		}
////		timer.Stop();
////		TimeCost	= timer.GetElapsedTime();
////
////		cout.precision(2);
////		cout<<"Image "<<setw(6)<<entity.ImageID<<": ";
////		cout<<setw(12)<<fixed<<TimeCost<<"s";
////
////		outLog.precision(3);
////		outLog<<"Image"<<setw(6)<<entity.ImageID<<":";
////		outLog<<setw(12)<<fixed<<TimeCost<<"s";
////
////		cout<<endl;
////		outLog<<endl;
////
////		if (tree.OrNodes[root].instances.size() > 0)
////		{
////			sprintf_s(fname, MAX_PATH, "%s\\%04d.jpg", strPN_FinalResult.c_str(), entity.ImageID);
////			ret	= DrawInstance(entity, tree.OrNodes[root].instances[0], fname);
////
////			for ( int zi = 0; zi < tree.AndNodes[0].instances[0].LeafNodeInfo.size(); ++zi )
////			{
////				double tt = 0;
////				tt += CMyMath::sqr(tree.AndNodes[0].instances[0].LeafNodeInfo[zi].node.x - gt_tree.AndNodes[0].instances[0].LeafNodeInfo[zi].node.x);
////				tt += CMyMath::sqr(tree.AndNodes[0].instances[0].LeafNodeInfo[zi].node.y - gt_tree.AndNodes[0].instances[0].LeafNodeInfo[zi].node.y);
////				ape += sqrt(tt);
////			}
////
////			for ( int zj = 0; zj < tree.AndNodes.size(); ++zj )
////			{
////				sprintf_s(fname, MAX_PATH, "%s\\%04d.Node_B.%02d.jpg", strPN_FinalResult.c_str(), entity.ImageID, zj);
////				//ret	= tree.AndNodes[zj].DrawInstanceNode(entity, fname);
////
////				if (strParseGroundPathName == "") continue;
////
////				CAndNode& cur_node = tree.AndNodes[zj];
////				vector<NodeInstanceType>& cur_list = cur_node.instances;
////				NodeInstanceType& cur_gt = gt_tree.AndNodes[zj].instances[0];
////
////				sprintf_s(strTemp, "GT Node %02d: %8.2lf  %8.2lf  %8.2lf  %8.2lf  =>  %10.6lf  %10.6lf  %10.6lf",
////					zj, cur_gt.center.x, cur_gt.center.y, CMyMath::FormatAngle(cur_gt.center.ori)*180/M_PI, cur_gt.center.scale, cur_gt.Score, cur_gt.ShapeScore, cur_gt.AppearanceScore);
////				outLog<<strTemp<<endl;
////				//gt_tree.AndNodes[zj].MakeMRFScore(model, tree, entity, cur_gt);
////
////				for ( int zo = 0; zo < cur_list.size(); ++zo )
////				{
////					//if (zo >= 64) break;
////					if (!cur_node.InstanceSimilar(model, cur_list[zo], cur_gt)) continue;
////					PerNodeRecall[zj] += 100.0 / ImageCount;
////					break;
////				}
////			}
////
////			//for ( int zj = 0; zj < tree.AndNodes.size(); ++zj )
////			//{
////			//	sprintf_s(strTemp, "Node %02d:  %.2lf  %.2lf  %.2lf  %.2lf", model.AndModels[zj].x, model.AndModels[zj].y, CMyMath::FormatAngle(model.AndModels[zj].ori)*180/M_PI, model.AndModels[zj].scale);
////			//	cout<<strTemp<<endl;
////			//	outLog<<strTemp<<endl;
////			//}
////
////			sprintf_s(fname, MAX_PATH, "%s\\%04d.txt", strPN_Boundary.c_str(), entity.ImageID);
////			ret	= PrintBoundary(tree.OrNodes[root].instances[0], entity.ImageID, fname);
////
////			//ret	= ParseStat.MakeAverageDist(entity, tree.OrNodes[root].instances[0], AvePos);
////			cout<<setw(12)<<fixed<<tree.OrNodes[root].instances[0].Score;
////			//cout<<setw(12)<<fixed<<AvePos;
////			//cout<<setw(12)<<fixed<<ParseStat.SumDist / ParseStat.DistCount;
////
////			outLog<<setw(12)<<fixed<<tree.OrNodes[root].instances[0].Score;
////			//outLog<<setw(12)<<fixed<<AvePos;
////			//outLog<<setw(12)<<fixed<<ParseStat.SumDist / ParseStat.DistCount;
////
////		}
////		else
////		{
////			cout<<setw(12)<<fixed<<"-1e6";
////			outLog<<setw(12)<<fixed<<"-1e6";
////		}
////
////		cout<<endl;
////		outLog<<endl;
////
////		//break;
////	}
////
////	ape /= ImageCount;
////	sprintf_s(strTemp, "APE = %.2lf", ape);
////	cout<<strTemp<<endl;
////	outLog<<strTemp<<endl;
////
////	for ( int zj = 0; zj < PerNodeRecall.size(); ++zj )
////	{
////		sprintf_s(strTemp, "Node %d Recall = %.2lf", zj, PerNodeRecall[zj]);
////		cout<<strTemp<<endl;
////		outLog<<strTemp<<endl;
////	}
////
////	inImageSet.close();
////	outLog.close();
////	//ret	= ParseStat.PrintSearchStatInfo("ParseState.txt");
////
////	return	1;
////}

////int	CProposalTree::ParseEntityTree(string strImageSetFileName, string strParseGroundPathName, string strFeaturePathName, int ParsedMode)
////{
////	vector<CHiBoostImageEntity>		ImageSet;
////	int					ImageCount;
////	int					ret;
////
////	ret			= ReadEntityFile(strImageSetFileName, strParseGroundPathName, ImageSet, strFeaturePathName, ParsedMode);
////	ImageCount	= (int) ImageSet.size();
////	ret			= ParseEntityTree(ImageSet, NULL);
////
////	return	1;
////}
////
////int	CProposalTree::ParseEntityTree(vector<CHiBoostImageEntity> &ImageSet, const char* ccpPN_ParseLog)
////{
////	InstanceTreeType	tree;
////	CTimer				timer;
////	ofstream			outLog("ParseLog.txt");
////	double				TimeCost, AvePos;
////	char				command[MAX_PATH], fname[MAX_PATH];
////	int					ImageCount	= (int) ImageSet.size();
////	int					ret;
////
////	sprintf_s(command, MAX_PATH, "rmdir /s /q FinalResult >:null");		system(command);
////	sprintf_s(command, MAX_PATH, "mkdir FinalResult >:null");			system(command);
////	sprintf_s(command, MAX_PATH, "rmdir /s /q Boundary >:null");		system(command);
////	sprintf_s(command, MAX_PATH, "mkdir Boundary >:null");				system(command);
////	ret	= ParseStat.InitAverageDist();
////
////	ImageCount	= (int) ImageSet.size();
////	for ( int t = 0; t < ImageCount; t++ )
////	{
////		tree				= template_tree;
////		tree.Width			= ImageSet[t].W;
////		tree.Height			= ImageSet[t].H;
////
////		if (strPN_DstParseImage != NULL)
////		{
////			sprintf_s(command, MAX_PATH, "rmdir /s /q %s\\%04d >:null", strPN_DstParseImage, t+1);		system(command);
////			sprintf_s(command, MAX_PATH, "mkdir %s\\%04d >:null", strPN_DstParseImage, t+1);				system(command);
////		}
////
////		timer.Reset();
////		timer.Start();
////		for ( int p = 0; p < (int) model.Rules.size(); p++ )
////		{
////			model.RuleStep	= p + 1;
////			ret	= AddSearchCenterIndex(tree, model.Rules[p]);
////			ret	= tree.OrNodes[root].BottomUpSearch(model, ImageSet[t], tree, strPN_DstParseImage);
////			ret	= tree.OrNodes[root].MakeSearchConstrain(model, tree, ImageSet[t]);
////		}
////		timer.Stop();
////		TimeCost	= timer.GetElapsedTime();
////
////		cout.precision(2);
////		cout<<"Image "<<setw(3)<<ImageSet[t].ImageID<<": ";
////		cout<<setw(12)<<fixed<<TimeCost<<"s";
////
////		outLog.precision(2);
////		outLog<<"Image"<<setw(4)<<ImageSet[t].ImageID<<":";
////		outLog<<setw(12)<<fixed<<TimeCost<<"s";
////
////		if (tree.OrNodes[root].instances.size() > 0)
////		{
////			sprintf_s(fname, MAX_PATH, "FinalResult\\%04d.jpg", ImageSet[t].ImageID);
////			ret	= DrawInstance(ImageSet[t], tree.OrNodes[root].instances[0], fname);
////
////			sprintf_s(fname, MAX_PATH, "Boundary\\%04d.txt", ImageSet[t].ImageID);
////			ret	= PrintBoundary(tree.OrNodes[root].instances[0], ImageSet[t].ImageID, fname);
////
////			ret	= ParseStat.MakeAverageDist(ImageSet[t], tree.OrNodes[root].instances[0], AvePos);
////			cout<<setw(12)<<fixed<<tree.OrNodes[root].instances[0].Score;
////			cout<<setw(12)<<fixed<<AvePos;
////			cout<<setw(12)<<fixed<<ParseStat.SumDist / ParseStat.DistCount;
////
////			outLog<<setw(12)<<fixed<<tree.OrNodes[root].instances[0].Score;
////			outLog<<setw(12)<<fixed<<AvePos;
////			outLog<<setw(12)<<fixed<<ParseStat.SumDist / ParseStat.DistCount;
////
////		}
////		cout<<endl;
////		outLog<<endl;
////	}
////
////	outLog.close();
////	ret	= ParseStat.PrintSearchStatInfo("ParseState.txt");
////	return	1;
////}

int CProposalTree::AddSearchCenterIndex(InstanceTreeType &tree, ArcModelType &Rule)
{
	bool	SearchStatus	= false;
	int		ret;

	if (Rule.ArcType == -1)
	{
		for ( int i = 0; i < (int) tree.AndNodes.size(); i++ )
		{
			tree.AndNodes[i].CenterIndex.clear();
			tree.AndNodes[i].parseInfo	= false;
		}

		for ( int i = 0; i < (int) tree.OrNodes.size(); i++ )
		{
			tree.OrNodes[i].CenterIndex.clear();
			tree.OrNodes[i].parseInfo	= false;
		}
	}

	if (Rule.ArcType == 0)
	{
		for ( int i = 0; i < (int) tree.AndNodes.size(); i++ )
		{
			tree.AndNodes[i].parseInfo	= true;
		}
		for ( int i = 0; i < (int) tree.OrNodes.size(); i++ )
		{
			tree.OrNodes[i].parseInfo	= true;
		}

		ret	= tree.OrNodes[Rule.RootID].AddSearchCenterIndex(model, tree, Rule, SearchStatus);
		ret	= tree.OrNodes[model.Root].SetNodeSearchStatus(model, tree);
	}

	return	1;
}

int CProposalTree::PrintBoundary(NodeInstanceType &Instance, int ImageID, string strBoundaryFileName)
{
	ofstream	outBoundary(strBoundaryFileName.c_str());
	int			LeafCount	= (int) Instance.LeafNodeInfo.size();

	outBoundary<<ImageID<<endl;
	outBoundary<<LeafCount<<endl;
	for (int i = 0; i < LeafCount; i++)
	{
		outBoundary.precision(1);
		outBoundary<<setw(8)<<fixed<<Instance.LeafNodeInfo[i].node.x;
		outBoundary<<setw(8)<<fixed<<Instance.LeafNodeInfo[i].node.y;
		outBoundary<<endl;
	}

	outBoundary.close();
	outBoundary.clear();
	return 1;
}

void CProposalTree::ReadStructFile(
	int								&LeafNodeAmount,
	vector<vector<vector<int>>>		&Hierarchy,
	vector<vector<int> >			&NodeIndex,
	string strFN_Struture)
{
	ifstream	inStructure(strFN_Struture.c_str());
	int			MaxLevel, NodeCount, ChildCount;

	inStructure>>MaxLevel;
	Hierarchy.resize(MaxLevel);
	NodeIndex.resize(MaxLevel);

	for ( int i = 0; i < MaxLevel; i++ )
	{
		inStructure>>NodeCount;
		Hierarchy[i].resize(NodeCount);
		NodeIndex[i].resize(NodeCount);
	}

	LeafNodeAmount = 0;

	for ( int i = 0; i < MaxLevel; i++ )
	{
		inStructure>>NodeCount;
		for ( int j = 0; j < NodeCount; j++ )
		{
			inStructure>>ChildCount;

			if (ChildCount < 1) ++LeafNodeAmount;

			Hierarchy[i][j].resize(ChildCount);
			for ( int k = 0; k < ChildCount; k++ )
			{
				inStructure>>Hierarchy[i][j][k];
			}
		}
	}

	inStructure.clear();
	inStructure.close();
}

void CProposalTree::CreateModelHierarchy(
	int								&LeafNodeAmount,
	vector<vector<vector<int>>>		&Hierarchy,
	vector<vector<int>>				&NodeIndex
	)
{
	int				OrCount		= 0;
	int				AndCount	= 0;

	// Root and leaf nodes
	model.Root	= 0;
	model.LeafModels.resize(LeafNodeAmount);
	for ( int i = 0; i < LeafNodeAmount; i++ )
	{
		model.LeafModels[i].LeafNodeID	= i;
		model.LeafModels[i].ori		= 0.0;
		model.LeafModels[i].x		= 0.0;
		model.LeafModels[i].y		= 0.0;
		//model.LeafModels[i]._scale	= 1.0;
	}

	// And nodes and Or nodes
	OrCount		= 0;
	AndCount	= 0;
	for ( int i = 0; i < (int) NodeIndex.size(); i=i+2 )
	{
		for ( int j = 0; j < (int) NodeIndex[i].size(); j++ )
		{
			NodeIndex[i][j]	= OrCount;
			OrCount++;
		}
	}
	for ( int i = 1; i < (int) NodeIndex.size(); i=i+2 )
	{
		for ( int j = 0; j < (int) NodeIndex[i].size(); j++ )
		{
			NodeIndex[i][j]	= AndCount;
			AndCount++;
		}
	}

	model.AndModels.resize(AndCount);
	model.OrModels.resize(OrCount);
	for ( int i = 0; i < (int)NodeIndex.size(); i=i+2 )
	{
		for ( int j = 0; j < (int)NodeIndex[i].size(); j++ )
		{
			int	OrNodeID	= NodeIndex[i][j];

			model.OrModels[OrNodeID].OrNodeID	= OrNodeID;
			model.OrModels[OrNodeID].Level = i/2;
			model.OrModels[OrNodeID].Children.resize(Hierarchy[i][j].size());
			for ( int k = 0; k < (int) Hierarchy[i][j].size(); k++ )
			{
				model.OrModels[OrNodeID].Children[k]	= NodeIndex[i+1][Hierarchy[i][j][k]];
			}
		}
	}
	for ( int i = 1; i < (int)NodeIndex.size(); i=i+2 )
	{
		for ( int j = 0; j < (int)NodeIndex[i].size(); j++ )
		{
			int	AndNodeID	= NodeIndex[i][j];

			model.AndModels[AndNodeID].AndNodeID	= AndNodeID;
			model.AndModels[AndNodeID].Level = i/2;			
			if (Hierarchy[i][j].size() > 0)
			//if (i < (int) NodeIndex.size() - 1)
			{
				model.AndModels[AndNodeID].LeafIndex	= -1;
				model.AndModels[AndNodeID].Children.resize(Hierarchy[i][j].size());
				for ( int k = 0; k < (int) Hierarchy[i][j].size(); k++ )
				{
					model.AndModels[AndNodeID].Children[k]	= NodeIndex[i+1][Hierarchy[i][j][k]];
				}
			}
			else
			{
				model.AndModels[AndNodeID].LeafIndex	= j; // Hierarchy[i][j][0];
				model.AndModels[AndNodeID].Children.clear();
			}
		}
	}
}

void CProposalTree::CreateNaiveModelFromLeafNodes(
	int								&LeafNodeAmount
	)
{
	InstanceTreeType	tree;
	int					LeafNodeCount	= (int) model.LeafModels.size();
	//int					Root;
	int					ret;

	tree.Root	= model.Root;
	tree.AndNodes.resize(model.AndModels.size());
	tree.OrNodes.resize(model.OrModels.size());
	for ( int i = 0; i < (int) model.AndModels.size(); i++ )
	{
		tree.AndNodes[i].createInfo	= false;
		tree.AndNodes[i].ModelID	= i;
		tree.AndNodes[i].leafIndex	= model.AndModels[i].LeafIndex;
		tree.AndNodes[i].children	= model.AndModels[i].Children;
	}
	for ( int i = 0; i < (int) model.OrModels.size(); i++ )
	{
		tree.OrNodes[i].createInfo		= false;
		tree.OrNodes[i].ModelID	= i;
		tree.OrNodes[i].children		= model.OrModels[i].Children;
	}

	// LeafDirInfo and LeafLenInfo
	model.LeafDirInfo.alloc(LeafNodeAmount, LeafNodeAmount);
	model.LeafLenInfo.alloc(LeafNodeAmount, LeafNodeAmount);
	for ( int i = 0; i < LeafNodeAmount; i++ )
	{
		for ( int j = 0; j < LeafNodeAmount; j++ )
		{
			if (i == j)	continue;

			double	x1	= 0.0; // LeafNodes[i].x
			double	y1	= 0.0; // LeafNodes[i].y
			double	x2	= 0.0; // LeafNodes[j].x
			double	y2	= 0.0; // LeafNodes[j].y

			double	len	= __max(sqrt((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2)), 1);
			double	ori	= 0.0; // (y2 > y1) ? (acos((x2-x1) / len)) : (-acos((x2-x1) / len));

			model.LeafDirInfo[i][j]	= ori;
			model.LeafLenInfo[i][j]	= len;
		}
	}

	//Root	= tree.Root;
	tree.OrNodes[model.Root].CreateNaiveModelFromNodes(model, tree);

	for ( int i = 0; i < (int) model.Curves.size(); i++ )
	{
		double	x1	= 0.0; // LeafNodes[model.Curves[i].LeafID1].x;
		double	y1	= 0.0; // LeafNodes[model.Curves[i].LeafID1].y;
		double	x2	= 0.0; // LeafNodes[model.Curves[i].LeafID2].x;
		double	y2	= 0.0; // LeafNodes[model.Curves[i].LeafID2].y;

		model.Curves[i].NodeLen	= __max(sqrt((x1-x2) * (x1-x2) + (y1-y2) * (y1-y2)), 1);
		model.Curves[i].NodeDir	= 0.0; // (y2 > y1) ? (acos((x2-x1) / model.Curves[i].NodeLen)) : (-acos((x2-x1) / model.Curves[i].NodeLen));
	}

	model.MaxLevel	= 0;
	ret	= PrepareModel();
	for ( int i = 0; i < (int) model.AndModels.size(); i++ )
	{
		model.AndModels[i].Threshold.assign(model.Rules.size(), 0);
		model.MaxLevel	= __max(model.AndModels[i].Level + 1, model.MaxLevel);
	}
}

void CProposalTree::MakeStandardModel(
	string strFN_Struture,
	const CHiBoostGroundTruthList& GT_List,
	string strPN_SaveInstance, string strPN_DrawInstance)
{
	int								LeafNodeAmount;
	vector<vector<vector<int>>>		Hierarchy;
	vector<vector<int>>				NodeIndex;

	ReadStructFile(LeafNodeAmount, Hierarchy, NodeIndex, strFN_Struture);
	CreateModelHierarchy(LeafNodeAmount, Hierarchy, NodeIndex);	

	model.Curves.clear();
	model.Rules.resize(1); model.Rules[0].ArcType = -1;

	CreateNaiveModelFromLeafNodes(LeafNodeAmount);

	char strTemp[10001];

	int ITERATION_AMOUNT = 50;
	int i_iteration;

	CSimpleTypeArray<InstanceTreeType> InstTreeList;
	ParseGroundTruthList(InstTreeList, GT_List, false, "", "", "");

	for ( i_iteration = 0; i_iteration < ITERATION_AMOUNT; ++i_iteration )
	{
		MakeStandardLeafPositionModel(InstTreeList, (i_iteration == 0));
		MakeStandardAndPositionModel(InstTreeList);

		CExternalTools::ConsoleTools::ClearCurrentLine();
		sprintf_s(strTemp, "Making Standard Model, Iteration %d/%d done;", i_iteration+1, ITERATION_AMOUNT);
		cout<<strTemp<<endl;

		//sprintf_s(strTemp, "InitModel.Iteration.%02d.txt", i_iteration);
		//this->SaveAndOrTreeModel(strTemp);
	}

	//ParseGroundTruthList(InstTreeList, GT_List, true, "", strPN_SaveInstance, "");
}

void CProposalTree::MakeStandardLeafPositionModel(CSimpleTypeArray<InstanceTreeType>& InstTreeList, bool fFirstTime)
{
	TMatrix<double>					LeafLenInfo, LeafDirInfo;
	TMatrix<int>					SumCount;
	vector<double>					LeafDir;
	vector<double>					LeafSumCount;
	int								LeafCount;

	int i_gt;
	char strTemp[10001];

	CExternalTools::ConsoleTools::ClearCurrentLine();
	sprintf_s(strTemp, "Reparsing Ground Truth Instances...");
	cout<<strTemp;

	for ( i_gt = 0; i_gt < (int)InstTreeList.Size; ++i_gt )
		this->RemakeTreeFromInst_NoEntity(InstTreeList.pElement[i_gt]);

	LeafCount	= (int) model.LeafModels.size();
	LeafLenInfo.alloc(LeafCount, LeafCount);
	LeafDirInfo.alloc(LeafCount, LeafCount);
	SumCount.alloc(LeafCount, LeafCount);

	CExternalTools::ConsoleTools::ClearCurrentLine();
	sprintf_s(strTemp, "Making Standard Leaf Position Model...");
	cout<<strTemp;

	for ( i_gt = 0; i_gt < (int)InstTreeList.Size; ++i_gt )
	{
		InstanceTreeType& iTree = InstTreeList.pElement[i_gt];

		NodeInstanceType	&Instance	= iTree.OrNodes[model.Root].instances[0];

		for ( int j = 0; j < (int) Instance.LeafNodeInfo.size(); j++ )
		{
			for ( int k = 0; k < (int) Instance.LeafNodeInfo.size(); k++ )
			{
				if (j == k)
				{
					continue;
				}

				int		p1	= Instance.LeafNodeInfo[j].LeafNodeIndex;
				int		p2	= Instance.LeafNodeInfo[k].LeafNodeIndex;
				double	x1	= Instance.LeafNodeInfo[j].node.x;
				double	y1	= Instance.LeafNodeInfo[j].node.y;
				double	x2	= Instance.LeafNodeInfo[k].node.x;
				double	y2	= Instance.LeafNodeInfo[k].node.y;

				double	d	= __max(1, sqrt((x1-x2)*(x1-x2) + (y1-y2) *(y1-y2)));
				double	r	= (y2 > y1) ? (acos((x2 - x1) / d)) : (-acos((x2 - x1) / d));
				double	dr	= OriDiff(model.LeafDirInfo[p1][p2], r);

				LeafLenInfo[p1][p2]		+= d;
				LeafDirInfo[p1][p2]		+= dr;
				SumCount[p1][p2]++;
			}
		}
	}

	for ( int i = 0; i < LeafCount; i++ )
	{
		LeafDirInfo[i][i]	= 0;
		LeafLenInfo[i][i]	= 0;
		for ( int j = 0; j < LeafCount; j++ )
		{
			if (SumCount[i][j] > 0)
			{
				LeafLenInfo[i][j]	/= SumCount[i][j];
				LeafDirInfo[i][j]	/= SumCount[i][j];
				LeafDirInfo[i][j]	+= model.LeafDirInfo[i][j];
			}
			else
			{
				LeafDirInfo[i][j]	= model.LeafDirInfo[i][j];
				LeafLenInfo[i][j]	= model.LeafLenInfo[i][j];
			}
		}
	}

	LeafDir.assign(LeafCount, 0);
	LeafSumCount.assign(LeafCount, 0);

	for ( i_gt = 0; i_gt < (int)InstTreeList.Size; ++i_gt )
	{
		InstanceTreeType& iTree = InstTreeList.pElement[i_gt];
		NodeInstanceType& Instance	= iTree.OrNodes[model.Root].instances[0];

		for ( int j = 0; j < (int) Instance.LeafNodeInfo.size(); j++ )
		{
			int		p	= Instance.LeafNodeInfo[j].LeafNodeIndex;
			double	dir	= Instance.LeafNodeInfo[j].node.ori;

			if (i_gt==0 && fFirstTime) model.LeafModels[p].ori = dir;

			double	rot	= OriDiff(2*model.LeafModels[p].ori, 2*dir) / 2;
			//double	rot	= OriDiff(2*model.LeafModels[p].ori, 2*dir) / 2;

			LeafDir[p]	+= rot;
			LeafSumCount[p]++;
		}
	}

	for ( int i = 0; i < LeafCount; i++ )
	{
		if (LeafSumCount[i] > 0)
		{
			LeafDir[i]	/= LeafSumCount[i];
			LeafDir[i]	+= model.LeafModels[i].ori;
		}
		else
		{
			LeafDir[i]	= model.LeafModels[i].ori;
		}
	}

	model.LeafDirInfo	= LeafDirInfo;
	model.LeafLenInfo	= LeafLenInfo;
	for ( int i = 0; i < LeafCount; i++ )
	{
		model.LeafModels[i].ori	= CMyMath::FormatAngle_Small(LeafDir[i]);
	}

	CExternalTools::ConsoleTools::ClearCurrentLine();
}

void CProposalTree::MakeStandardAndPositionModel(CSimpleTypeArray<InstanceTreeType>& InstTreeList)
{
	int i_gt;
	char strTemp[10001];

	CExternalTools::ConsoleTools::ClearCurrentLine();
	sprintf_s(strTemp, "Reparsing Ground Truth Instances...");
	cout<<strTemp;

	for ( i_gt = 0; i_gt < (int)InstTreeList.Size; ++i_gt )
		this->RemakeTreeFromInst_NoEntity(InstTreeList.pElement[i_gt]);

	CExternalTools::ConsoleTools::ClearCurrentLine();
	sprintf_s(strTemp, "Making Standard And Position Model...");
	cout<<strTemp;

	// Node To Node
	for ( int t = 0; t < (int) model.AndModels.size(); t++ )
	{
		if (model.AndModels[t].NodeType == 1)
		{
			MakeStandardAndPositionNode(InstTreeList, t);
			MakeStandardTripletNode(InstTreeList, t);
		}
	}

	CExternalTools::ConsoleTools::ClearCurrentLine();
}

void CProposalTree::MakeStandardAndPositionNode(CSimpleTypeArray<InstanceTreeType>& InstTreeList, int NodeIndex)
{
	CAndNodeModel		&CurrModel		= model.AndModels[NodeIndex];
	TMatrix<double>		MeanNodeScale, MeanNodeRotate;
	TMatrix<int>		SumCount;
	vector<double>		LeafLen, LeafDir;
	vector<int>			LeafSumCount, LeafIndex;
	int					ChildCount		= (int) CurrModel.Children.size();
	int					ModelCount		= CurrModel.ModelCount;
	int					LeafCount		= (int) model.LeafModels.size();
	int					CurLeafCount	= (int) CurrModel.LeafCenterInfo.size();
	int					LeafID;

	// Initialize
	LeafLen.assign(CurLeafCount, 0);
	LeafDir.assign(CurLeafCount, 0);
	LeafSumCount.assign(CurLeafCount, 0);
	SumCount.alloc(ModelCount, ModelCount);
	MeanNodeScale.alloc(ModelCount, ModelCount);
	MeanNodeRotate.alloc(ModelCount, ModelCount);
	LeafIndex.assign(LeafCount, 0);
	for ( int i = 0; i < CurLeafCount; i++ )
	{
		LeafID				= CurrModel.LeafCenterInfo[i].LeafID;
		LeafIndex[LeafID]	= i;
	}

	for ( int t = 0; t < (int)InstTreeList.Size; t++ )
	{
		CAndNode	&CurrNode	= InstTreeList.pElement[t].AndNodes[NodeIndex];
		double		Scale, Rotate;

		for ( int i = 0; i < (int) CurrNode.instances.size(); i++ )
		{
			Scale	= CurrNode.instances[i].center.scale;
			Rotate	= CurrNode.instances[i].center.ori;

			for ( int p = 0; p < (int) CurrNode.instances[i].LeafNodeInfo.size(); p++ )
			{
				int		m	= CurrNode.instances[i].LeafNodeInfo[p].LeafNodeIndex;
				double	x1	= CurrNode.instances[i].center.x;
				double	y1	= CurrNode.instances[i].center.y;
				double	x2	= CurrNode.instances[i].LeafNodeInfo[p].node.x;
				double	y2	= CurrNode.instances[i].LeafNodeInfo[p].node.y;

				double	d	= __max(1, sqrt((x1-x2)*(x1-x2) + (y1-y2) *(y1-y2)));
				double	r	= (y2 > y1) ? (acos((x2 - x1) / d)) : (-acos((x2 - x1) / d));
				double	rr	= (r >= 0) ? r : (r + 2 * M_PI);
				double	dr	= OriDiff(CurrModel.LeafCenterInfo[LeafIndex[m]].ori, r);

				LeafLen[LeafIndex[m]]	+= d;
				LeafDir[LeafIndex[m]]	+= dr;
				LeafSumCount[LeafIndex[m]]++;
			}

			for ( int p1 = 0; p1 < ChildCount; p1++ )
			{
				for ( int p2 = 0; p2 < ChildCount; p2++ )
				{
					if (p1 == p2)
					{
						continue;
					}

					double	x1	= CurrNode.instances[i].ChildCenters[p1].x;
					double	y1	= CurrNode.instances[i].ChildCenters[p1].y;
					double	x2	= CurrNode.instances[i].ChildCenters[p2].x;
					double	y2	= CurrNode.instances[i].ChildCenters[p2].y;
					double	s1	= CurrNode.instances[i].ChildCenters[p1].scale;
					double	s2	= CurrNode.instances[i].ChildCenters[p2].scale;
					double	r1	= CurrNode.instances[i].ChildCenters[p1].ori;
					double	r2	= CurrNode.instances[i].ChildCenters[p2].ori;
					int		m1	= CurrNode.instances[i].ChildCenters[p1].OrIndex + CurrModel.NodeModelIndex[p1];
					int		m2	= CurrNode.instances[i].ChildCenters[p2].OrIndex + CurrModel.NodeModelIndex[p2];

					double	d	= __max(1, sqrt((x1-x2)*(x1-x2) + (y1-y2) *(y1-y2)));
					double	r	= (y2 > y1) ? (acos((x2 - x1) / d)) : (-acos((x2 - x1) / d));
					double	rr	= (r >= 0) ? r : (r + 2 * M_PI);
					double	dr	= OriDiff(CurrModel.NodeDirInfo[m1][m2], r);

					MeanNodeScale[m1][m2]	+= d;
					MeanNodeRotate[m1][m2]	+= dr;
					SumCount[m1][m2]++;
				}
			}
		}
	}

	for ( int i = 0; i < ModelCount; i++ )
	{
		MeanNodeScale[i][i]		= 0;
		MeanNodeRotate[i][i]	= 0;
		for ( int j = 0; j < ModelCount; j++ )
		{
			if (SumCount[i][j] > 0)
			{
				MeanNodeScale[i][j]		/= SumCount[i][j];
				MeanNodeRotate[i][j]	/= SumCount[i][j];
				MeanNodeRotate[i][j]	+= CurrModel.NodeDirInfo[i][j];
			}
			else if (i != j)
			{
				MeanNodeScale[i][j]		= CurrModel.NodeLenInfo[i][j];
				MeanNodeRotate[i][j]	= CurrModel.NodeDirInfo[i][j];
			}
		}
	}

	for ( int i = 0; i < CurLeafCount; i++ )
	{
		if (LeafSumCount[i] > 0)
		{
			LeafLen[i]	/= LeafSumCount[i];
			LeafDir[i]	/= LeafSumCount[i];
			LeafDir[i]	+= CurrModel.LeafCenterInfo[i].ori;
		}
		else
		{
			LeafLen[i]	= CurrModel.LeafCenterInfo[i].len;
			LeafDir[i]	= CurrModel.LeafCenterInfo[i].ori;
		}
	}

	CurrModel.NodeLenInfo	= MeanNodeScale;
	CurrModel.NodeDirInfo	= MeanNodeRotate;
	for ( int i = 0; i < CurLeafCount; i++ )
	{
		CurrModel.LeafCenterInfo[i].len	= LeafLen[i];
		CurrModel.LeafCenterInfo[i].ori	= LeafDir[i];
	}
}

void CProposalTree::MakeStandardTripletNode(CSimpleTypeArray<InstanceTreeType>& InstTreeList, int NodeIndex)
{
	CAndNodeModel		&CurrModel		= model.AndModels[NodeIndex];
	int					AngleDimension	= 6;
	int					GeoDimension	= 12;
	int					TripletCount	= (int)CurrModel.triplets.size();
	TMatrix<double>		MeanTriplet, VarTriplet;
	vector<int>			SumCount;
	int					ret;

	SumCount.assign(TripletCount, 0);
	MeanTriplet.alloc(TripletCount, GeoDimension);
	VarTriplet.alloc(TripletCount, GeoDimension);

	for ( int t = 0; t < (int)InstTreeList.Size; t++ )
	{
		CAndNode		&CurrNode	= InstTreeList.pElement[t].AndNodes[NodeIndex];
		vector<double>	GeoFeature;

		for ( int i = 0; i < (int) CurrNode.instances.size(); i++ )
		{
			for ( int j = 0; j < (int) CurrModel.triplets.size(); j++ )
			{
				int		p1	= CurrModel.triplets[i].p1;
				int		p2	= CurrModel.triplets[i].p2;
				int		p3	= CurrModel.triplets[i].p3;

				BasicInstInfoType	&n1	= CurrNode.instances[i].ChildCenters[p1];
				BasicInstInfoType	&n2	= CurrNode.instances[i].ChildCenters[p2];
				BasicInstInfoType	&n3	= CurrNode.instances[i].ChildCenters[p3];

				if ((CurrModel.triplets[i].m1 != CurrNode.instances[i].ChildCenters[p1].OrIndex) ||
					(CurrModel.triplets[i].m2 != CurrNode.instances[i].ChildCenters[p2].OrIndex) ||
					(CurrModel.triplets[i].m3 != CurrNode.instances[i].ChildCenters[p3].OrIndex))
				{
					continue;
				}

				ret	= CurrNode.MakeTripletFeature(CurrModel.triplets[i], model, n1, n2, n3, GeoFeature, CurrNode.instances[i].center);

				SumCount[j]++;
				for ( int p = 0; p < AngleDimension; p++ )
				{
					double	dr			= OriDiff(CurrModel.triplets[j].feature[p], GeoFeature[p]);
					MeanTriplet[j][p]	+= dr;
					VarTriplet[j][p]	+= dr * dr;
				}
				for ( int p = AngleDimension; p < GeoDimension; p++ )
				{
					MeanTriplet[j][p]	+= GeoFeature[p];
					VarTriplet[j][p]	+= GeoFeature[p] * GeoFeature[p];
				}
			}
		}
	}

	for ( int t = 0; t < TripletCount; t++ )
	{
		for ( int p = 0; p < AngleDimension; p++ )
		{
			MeanTriplet[t][p]	/= SumCount[t];
			VarTriplet[t][p]	/= SumCount[t];
			VarTriplet[t][p]	-= MeanTriplet[t][p] * MeanTriplet[t][p];
			VarTriplet[t][p]	= sqrt(VarTriplet[t][p]);
			MeanTriplet[t][p]	+= CurrModel.triplets[t].feature[p];
		}

		for ( int p = AngleDimension; p < GeoDimension; p++ )
		{
			MeanTriplet[t][p]	/= SumCount[t];
			VarTriplet[t][p]	/= SumCount[t];
			VarTriplet[t][p]	-= MeanTriplet[t][p] * MeanTriplet[t][p];
			VarTriplet[t][p]	= sqrt(VarTriplet[t][p]);
		}
	}

	for ( int t = 0; t < TripletCount; t++ )
	{
		for ( int p = 0; p < GeoDimension; p++ )
		{
			CurrModel.triplets[t].feature[p]	= MeanTriplet[t][p];
			CurrModel.triplets[t].variance[p]	= VarTriplet[t][p];
		}
	}
}

//int CProposalTree::MakeStandardModel(string strImageSetFileName, string strParseGroundPathName, string strFeaturePathName)
//{
//	vector<CHiBoostImageEntity>		ImageSet;
//	int					ImageCount;
//	int					Times	= 10;
//	int					ret;
//
//	ret			= ReadEntityFile(strImageSetFileName, strParseGroundPathName, ImageSet, strFeaturePathName, 1);
//	ImageCount	= (int) ImageSet.size();
//
//	for ( int i = 0; i < Times; i++ )
//	{
//		ret	= MakeStandardLeafPositionModel(ImageSet, (i==0));
//		ret	= MakeStandardAndPositionModel(ImageSet);
//	}
//
//	return	1;
//}
//
//int CProposalTree::MakeStandardLeafPositionModel(vector<CHiBoostImageEntity> &ImageSet, bool fFirstTime)
//{
//	vector<InstanceTreeType>		Trees;
//	TMatrix<double>					LeafLenInfo, LeafDirInfo;
//	TMatrix<int>					SumCount;
//	vector<double>					LeafDir;
//	vector<double>					LeafSumCount;
//	int								LeafCount;
//	int								ret;
//
//	LeafCount	= (int) model.LeafModels.size();
//	LeafLenInfo.alloc(LeafCount, LeafCount);
//	LeafDirInfo.alloc(LeafCount, LeafCount);
//	SumCount.alloc(LeafCount, LeafCount);
//
//	Trees.assign(ImageSet.size(), template_tree);
//	model.RuleStep	= (int) model.Rules.size();
//	ret				= MakeTreeFromGround(Trees, ImageSet);
//
//	for ( int i = 0; i < (int) Trees.size(); i++ )
//	{
//		NodeInstanceType	&Instance	= Trees[i].OrNodes[model.Root].instances[0];
//
//		for ( int j = 0; j < (int) Instance.LeafNodeInfo.size(); j++ )
//		{
//			for ( int k = 0; k < (int) Instance.LeafNodeInfo.size(); k++ )
//			{
//				if (j == k)
//				{
//					continue;
//				}
//
//				int		p1	= Instance.LeafNodeInfo[j].LeafNodeIndex;
//				int		p2	= Instance.LeafNodeInfo[k].LeafNodeIndex;
//				double	x1	= Instance.LeafNodeInfo[j].node.x;
//				double	y1	= Instance.LeafNodeInfo[j].node.y;
//				double	x2	= Instance.LeafNodeInfo[k].node.x;
//				double	y2	= Instance.LeafNodeInfo[k].node.y;
//
//				double	d	= __max(1, sqrt((x1-x2)*(x1-x2) + (y1-y2) *(y1-y2)));
//				double	r	= (y2 > y1) ? (acos((x2 - x1) / d)) : (-acos((x2 - x1) / d));
//				double	dr	= OriDiff(model.LeafDirInfo[p1][p2], r);
//
//				LeafLenInfo[p1][p2]		+= d;
//				LeafDirInfo[p1][p2]		+= dr;
//				SumCount[p1][p2]++;
//			}
//		}
//	}
//
//	for ( int i = 0; i < LeafCount; i++ )
//	{
//		LeafDirInfo[i][i]	= 0;
//		LeafLenInfo[i][i]	= 0;
//		for ( int j = 0; j < LeafCount; j++ )
//		{
//			if (SumCount[i][j] > 0)
//			{
//				LeafLenInfo[i][j]	/= SumCount[i][j];
//				LeafDirInfo[i][j]	/= SumCount[i][j];
//				LeafDirInfo[i][j]	+= model.LeafDirInfo[i][j];
//			}
//			else
//			{
//				LeafDirInfo[i][j]	= model.LeafDirInfo[i][j];
//				LeafLenInfo[i][j]	= model.LeafLenInfo[i][j];
//			}
//		}
//	}
//
//	LeafDir.assign(LeafCount, 0);
//	LeafSumCount.assign(LeafCount, 0);
//
//	for ( int i = 0; i < (int) Trees.size(); i++ )
//	{
//		NodeInstanceType	&Instance	= Trees[i].OrNodes[model.Root].instances[0];
//
//		for ( int j = 0; j < (int) Instance.LeafNodeInfo.size(); j++ )
//		{
//			int		p	= Instance.LeafNodeInfo[j].LeafNodeIndex;
//			double	dir	= Instance.LeafNodeInfo[j].node.ori;
//			
//			if (i==0 && fFirstTime) model.LeafModels[p].ori = dir;
//
//			double	rot	= OriDiff(2*model.LeafModels[p].ori, 2*dir) / 2;
//			//double	rot	= OriDiff(2*model.LeafModels[p].ori, 2*dir) / 2;
//
//			LeafDir[p]	+= rot;
//			LeafSumCount[p]++;
//		}
//	}
//
//	for ( int i = 0; i < LeafCount; i++ )
//	{
//		if (LeafSumCount[i] > 0)
//		{
//			LeafDir[i]	/= LeafSumCount[i];
//			LeafDir[i]	+= model.LeafModels[i].ori;
//		}
//		else
//		{
//			LeafDir[i]	= model.LeafModels[i].ori;
//		}
//	}
//
//	model.LeafDirInfo	= LeafDirInfo;
//	model.LeafLenInfo	= LeafLenInfo;
//	for ( int i = 0; i < LeafCount; i++ )
//	{
//		model.LeafModels[i].ori	= CMyMath::FormatAngle_Small(LeafDir[i]);
//	}
//
//	return	1;
//}
//
//int CProposalTree::MakeStandardAndPositionNode(vector<InstanceTreeType> &Trees, int NodeID)
//{
//	CAndNodeModel		&CurrModel		= model.AndModels[NodeID];
//	TMatrix<double>		MeanNodeScale, MeanNodeRotate;
//	TMatrix<int>		SumCount;
//	vector<double>		LeafLen, LeafDir;
//	vector<int>			LeafSumCount, LeafIndex;
//	int					ChildCount		= (int) CurrModel.Children.size();
//	int					ModelCount		= CurrModel.ModelCount;
//	int					LeafCount		= (int) model.LeafModels.size();
//	int					CurLeafCount	= (int) CurrModel.LeafCenterInfo.size();
//	int					LeafID;
//
//	// Initialize
//	LeafLen.assign(CurLeafCount, 0);
//	LeafDir.assign(CurLeafCount, 0);
//	LeafSumCount.assign(CurLeafCount, 0);
//	SumCount.alloc(ModelCount, ModelCount);
//	MeanNodeScale.alloc(ModelCount, ModelCount);
//	MeanNodeRotate.alloc(ModelCount, ModelCount);
//	LeafIndex.assign(LeafCount, 0);
//	for ( int i = 0; i < CurLeafCount; i++ )
//	{
//		LeafID				= CurrModel.LeafCenterInfo[i].LeafID;
//		LeafIndex[LeafID]	= i;
//	}
//
//	for ( int t = 0; t < (int) Trees.size(); t++ )
//	{
//		CAndNode	&CurrNode	= Trees[t].AndNodes[NodeID];
//		double		Scale, Rotate;
//
//		for ( int i = 0; i < (int) CurrNode.instances.size(); i++ )
//		{
//			Scale	= CurrNode.instances[i].center.scale;
//			Rotate	= CurrNode.instances[i].center.ori;
//
//			for ( int p = 0; p < (int) CurrNode.instances[i].LeafNodeInfo.size(); p++ )
//			{
//				int		m	= CurrNode.instances[i].LeafNodeInfo[p].LeafNodeIndex;
//				double	x1	= CurrNode.instances[i].center.x;
//				double	y1	= CurrNode.instances[i].center.y;
//				double	x2	= CurrNode.instances[i].LeafNodeInfo[p].node.x;
//				double	y2	= CurrNode.instances[i].LeafNodeInfo[p].node.y;
//
//				double	d	= __max(1, sqrt((x1-x2)*(x1-x2) + (y1-y2) *(y1-y2)));
//				double	r	= (y2 > y1) ? (acos((x2 - x1) / d)) : (-acos((x2 - x1) / d));
//				double	rr	= (r >= 0) ? r : (r + 2 * M_PI);
//				double	dr	= OriDiff(CurrModel.LeafCenterInfo[LeafIndex[m]].ori, r);
//
//				LeafLen[LeafIndex[m]]	+= d;
//				LeafDir[LeafIndex[m]]	+= dr;
//				LeafSumCount[LeafIndex[m]]++;
//			}
//
//			for ( int p1 = 0; p1 < ChildCount; p1++ )
//			{
//				for ( int p2 = 0; p2 < ChildCount; p2++ )
//				{
//					if (p1 == p2)
//					{
//						continue;
//					}
//
//					double	x1	= CurrNode.instances[i].ChildCenters[p1].x;
//					double	y1	= CurrNode.instances[i].ChildCenters[p1].y;
//					double	x2	= CurrNode.instances[i].ChildCenters[p2].x;
//					double	y2	= CurrNode.instances[i].ChildCenters[p2].y;
//					double	s1	= CurrNode.instances[i].ChildCenters[p1].scale;
//					double	s2	= CurrNode.instances[i].ChildCenters[p2].scale;
//					double	r1	= CurrNode.instances[i].ChildCenters[p1].ori;
//					double	r2	= CurrNode.instances[i].ChildCenters[p2].ori;
//					int		m1	= CurrNode.instances[i].ChildCenters[p1].OrIndex + CurrModel.NodeModelIndex[p1];
//					int		m2	= CurrNode.instances[i].ChildCenters[p2].OrIndex + CurrModel.NodeModelIndex[p2];
//
//					double	d	= __max(1, sqrt((x1-x2)*(x1-x2) + (y1-y2) *(y1-y2)));
//					double	r	= (y2 > y1) ? (acos((x2 - x1) / d)) : (-acos((x2 - x1) / d));
//					double	rr	= (r >= 0) ? r : (r + 2 * M_PI);
//					double	dr	= OriDiff(CurrModel.NodeDirInfo[m1][m2], r);
//
//					MeanNodeScale[m1][m2]	+= d;
//					MeanNodeRotate[m1][m2]	+= dr;
//					SumCount[m1][m2]++;
//				}
//			}
//		}
//	}
//
//	for ( int i = 0; i < ModelCount; i++ )
//	{
//		MeanNodeScale[i][i]		= 0;
//		MeanNodeRotate[i][i]	= 0;
//		for ( int j = 0; j < ModelCount; j++ )
//		{
//			if (SumCount[i][j] > 0)
//			{
//				MeanNodeScale[i][j]		/= SumCount[i][j];
//				MeanNodeRotate[i][j]	/= SumCount[i][j];
//				MeanNodeRotate[i][j]	+= CurrModel.NodeDirInfo[i][j];
//			}
//			else if (i != j)
//			{
//				MeanNodeScale[i][j]		= CurrModel.NodeLenInfo[i][j];
//				MeanNodeRotate[i][j]	= CurrModel.NodeDirInfo[i][j];
//			}
//		}
//	}
//
//	for ( int i = 0; i < CurLeafCount; i++ )
//	{
//		if (LeafSumCount[i] > 0)
//		{
//			LeafLen[i]	/= LeafSumCount[i];
//			LeafDir[i]	/= LeafSumCount[i];
//			LeafDir[i]	+= CurrModel.LeafCenterInfo[i].ori;
//		}
//		else
//		{
//			LeafLen[i]	= CurrModel.LeafCenterInfo[i].len;
//			LeafDir[i]	= CurrModel.LeafCenterInfo[i].ori;
//		}
//	}
//
//	CurrModel.NodeLenInfo	= MeanNodeScale;
//	CurrModel.NodeDirInfo	= MeanNodeRotate;
//	for ( int i = 0; i < CurLeafCount; i++ )
//	{
//		CurrModel.LeafCenterInfo[i].len	= LeafLen[i];
//		CurrModel.LeafCenterInfo[i].ori	= LeafDir[i];
//	}
//
//	return	1;
//}
//
//int CProposalTree::MakeStandardTripletNode(vector<InstanceTreeType> &Trees, int NodeID)
//{
//	CAndNodeModel		&CurrModel		= model.AndModels[NodeID];
//	int					AngleDimension	= 6;
//	int					GeoDimension	= 12;
//	int					TripletCount	= (int) CurrModel.triplets.size();
//	TMatrix<double>		MeanTriplet, VarTriplet;
//	vector<int>			SumCount;
//	int					ret;
//
//	SumCount.assign(TripletCount, 0);
//	MeanTriplet.alloc(TripletCount, GeoDimension);
//	VarTriplet.alloc(TripletCount, GeoDimension);
//
//	for ( int t = 0; t < (int) Trees.size(); t++ )
//	{
//		CAndNode		&CurrNode	= Trees[t].AndNodes[NodeID];
//		vector<double>	GeoFeature;
//
//		for ( int i = 0; i < (int) CurrNode.instances.size(); i++ )
//		{
//			for ( int j = 0; j < (int) CurrModel.triplets.size(); j++ )
//			{
//				int		p1	= CurrModel.triplets[i].p1;
//				int		p2	= CurrModel.triplets[i].p2;
//				int		p3	= CurrModel.triplets[i].p3;
//
//				BasicInstInfoType	&n1	= CurrNode.instances[i].ChildCenters[p1];
//				BasicInstInfoType	&n2	= CurrNode.instances[i].ChildCenters[p2];
//				BasicInstInfoType	&n3	= CurrNode.instances[i].ChildCenters[p3];
//
//				if ((CurrModel.triplets[i].m1 != CurrNode.instances[i].ChildCenters[p1].OrIndex) ||
//					(CurrModel.triplets[i].m2 != CurrNode.instances[i].ChildCenters[p2].OrIndex) ||
//					(CurrModel.triplets[i].m3 != CurrNode.instances[i].ChildCenters[p3].OrIndex))
//				{
//					continue;
//				}
//
//				ret	= CurrNode.MakeTripletFeature(n1, n2, n3, GeoFeature, CurrNode.instances[i].center);
//
//				SumCount[j]++;
//				for ( int p = 0; p < AngleDimension; p++ )
//				{
//					double	dr			= OriDiff(CurrModel.triplets[j].feature[p], GeoFeature[p]);
//					MeanTriplet[j][p]	+= dr;
//					VarTriplet[j][p]	+= dr * dr;
//				}
//				for ( int p = AngleDimension; p < GeoDimension; p++ )
//				{
//					MeanTriplet[j][p]	+= GeoFeature[p];
//					VarTriplet[j][p]	+= GeoFeature[p] * GeoFeature[p];
//				}
//			}
//		}
//	}
//
//	for ( int t = 0; t < TripletCount; t++ )
//	{
//		for ( int p = 0; p < AngleDimension; p++ )
//		{
//			MeanTriplet[t][p]	/= SumCount[t];
//			VarTriplet[t][p]	/= SumCount[t];
//			VarTriplet[t][p]	-= MeanTriplet[t][p] * MeanTriplet[t][p];
//			VarTriplet[t][p]	= sqrt(VarTriplet[t][p]);
//			MeanTriplet[t][p]	+= CurrModel.triplets[t].feature[p];
//		}
//
//		for ( int p = AngleDimension; p < GeoDimension; p++ )
//		{
//			MeanTriplet[t][p]	/= SumCount[t];
//			VarTriplet[t][p]	/= SumCount[t];
//			VarTriplet[t][p]	-= MeanTriplet[t][p] * MeanTriplet[t][p];
//			VarTriplet[t][p]	= sqrt(VarTriplet[t][p]);
//		}
//	}
//
//	for ( int t = 0; t < TripletCount; t++ )
//	{
//		for ( int p = 0; p < GeoDimension; p++ )
//		{
//			CurrModel.triplets[t].feature[p]	= MeanTriplet[t][p];
//			CurrModel.triplets[t].variance[p]	= VarTriplet[t][p];
//		}
//	}
//
//	return	1;
//}
//
//int CProposalTree::MakeStandardAndPositionModel(vector<CHiBoostImageEntity> &ImageSet)
//{
//	vector<InstanceTreeType>		Trees;
//	TMatrix<double>					LeafLenInfo, LeafDirInfo;
//	TMatrix<int>					SumCount;
//	int								LeafCount;
//	int								ret;
//
//	LeafCount	= (int) model.LeafModels.size();
//	LeafLenInfo.alloc(LeafCount, LeafCount);
//	LeafDirInfo.alloc(LeafCount, LeafCount);
//	SumCount.alloc(LeafCount, LeafCount);
//
//	Trees.assign(ImageSet.size(), template_tree);
//	model.RuleStep	= (int) model.Rules.size();
//	ret				= MakeTreeFromGround(Trees, ImageSet);
//
//	// Node To Node
//	for ( int t = 0; t < (int) model.AndModels.size(); t++ )
//	{
//		if (model.AndModels[t].NodeType == 1)
//		{
//			ret	= MakeStandardAndPositionNode(Trees, t);
//			ret	= MakeStandardTripletNode(Trees, t);
//		}
//	}
//
//	return	1;
//}
//
//int CProposalTree::InitAppearModel(string strImageSetFileName, string strParseGroundPathName, string strFeaturePathName)
//{
//	vector<CHiBoostImageEntity>		ImageSet;
//	int					ret;
//
//	ret	= ReadEntityFile(strImageSetFileName, strParseGroundPathName, ImageSet, strFeaturePathName, 1);
//	ret	= InitLeafAppearOfModel(ImageSet);
//
//	return	1;
//}
//
//int CProposalTree::InitLeafAppearOfModel(vector<CHiBoostImageEntity> &ImageSet)
//{
//	////vector<double>		MaxValues, MinValues;
//	int					ImageCount, LeafCount;
//	////int					BinSize, FeaSize;
//	int					ret;
//
//	////BinSize		= g_Parameter.LeafBinCount;
//	////FeaSize		= (int) ImageSet[0].FeatureSize;
//	LeafCount	= (int) model.LeafModels.size();
//	ImageCount	= (int) ImageSet.size();
//
//	for ( int i = 0; i < (int)model.AndModels.size(); ++i )
//		model.AndModels[i].AppearanceWeight = 1.0;
//
//	for ( int i = 0; i < LeafCount; i++ )
//	{
//		////model.LeafModels[i].Weights.assign(FeaSize, 0.1);
//		////model.LeafModels[i].FeatureModel.resize(FeaSize);
//		////for ( int j = 0; j < FeaSize; j++ )
//		////{
//		////	model.LeafModels[i].FeatureModel[j].BinSize	= BinSize;
//		////	model.LeafModels[i].FeatureModel[j].MaxValue	= 0;
//		////	model.LeafModels[i].FeatureModel[j].MinValue	= 0;
//		////	model.LeafModels[i].FeatureModel[j].Smooth	= 0;
//		////	model.LeafModels[i].FeatureModel[j].BinValue.assign(BinSize, 0);
//		////}
//	}
//
//	////MaxValues.assign(FeaSize, - DBL_MAX);
//	////MinValues.assign(FeaSize, DBL_MAX);
//	////for ( int p = 0; p < FeaSize; p++ )
//	////{
//	////	for ( int t = 0; t < ImageCount; t++ )
//	////	{
//	////		for ( int i = 0; i < (int) ImageSet[t].nodes.size(); i++ )
//	////		{
//	////			MaxValues[p]	= __max(MaxValues[p], ImageSet[t].nodes[i].feature[p]);
//	////			MinValues[p]	= __min(MinValues[p], ImageSet[t].nodes[i].feature[p]);
//	////		}
//	////	}
//	////}
//
//	////cout<<"FeaSize: "<<FeaSize<<endl;
//	////for ( int LeafID = 0; LeafID < model.LeafModels.size(); LeafID++ )
//	////{
//	////	CLeafNodeModel	&CurrModel	= model.LeafModels[LeafID];
//
//	////	for ( int p = 0; p < FeaSize; p++ )
//	////	{
//	////		vector<double>		PerTrainBkg(BinSize, 1);
//	////		vector<double>		PerTrainObj(BinSize, 1);
//	////		double				MaxValue		= MaxValues[p];
//	////		double				MinValue		= MinValues[p];
//	////		double				Step			= (MaxValue - MinValue) / BinSize;
//	////		int					BinID			= 0;
//	////		int					BkgTrainCount	= BinSize;
//	////		int					ObjTrainCount	= BinSize;
//	////		int					NodeID;
//
//	////		cout<<LeafID<<"		"<<p<<"		\r";
//
//	////		for ( int t = 0; t < ImageCount; t++ )
//	////		{
//	////			for ( int i = 0; i < ImageSet[t].nodes.size(); i++ )
//	////			{
//	////				BinID	= int((ImageSet[t].nodes[i].feature[p] - MinValue) / Step);
//	////				//BinID	= int((ImageSet[t].nodes[i].feature[p] - MinValue) / Step + 0.5);
//	////				BinID	= __max(0, __min(BinSize - 1, BinID));
//	////				PerTrainBkg[BinID]	+= 1.0;
//	////				BkgTrainCount++;
//	////			}
//
//	////			bool	LeafExisted = false;
//	////			int		LeafIndex;
//	////			for ( int i = 0; i < ImageSet[t].ParseNodes.size(); i++ )
//	////			{
//	////				if (ImageSet[t].ParseNodes[i].LeafNodeIndex == LeafID)
//	////				{
//	////					LeafExisted	= true;
//	////					LeafIndex	= i;
//	////					break;
//	////				}
//	////			}
//	////			if (LeafExisted)
//	////			{
//	////				ret		= ImageSet[t].FindNearestNodes(ImageSet[t].ParseNodes[LeafIndex].node.x, ImageSet[t].ParseNodes[LeafIndex].node.y, NodeID);
//	////				BinID	= int((ImageSet[t].nodes[NodeID].feature[p] - MinValue) / Step);
//	////				//BinID	= int((ImageSet[t].nodes[NodeID].feature[p] - MinValue) / Step + 0.5);
//	////				BinID	= __max(0, __min(BinSize - 1, BinID));
//	////				PerTrainObj[BinID]	+= 1.0;
//	////				ObjTrainCount++;
//	////			}
//	////		}
//
//	////		for ( int i = 0; i < BinSize; i++ )
//	////		{
//	////			PerTrainObj[i]	/= ObjTrainCount;
//	////			PerTrainBkg[i]	/= BkgTrainCount;
//	////		}
//
//	////		CurrModel.FeatureModel[p].BinSize	= BinSize;
//	////		CurrModel.FeatureModel[p].MaxValue	= MaxValue;
//	////		CurrModel.FeatureModel[p].MinValue	= MinValue;
//	////		CurrModel.FeatureModel[p].Smooth	= 1;
//	////		CurrModel.FeatureModel[p].BinValue.assign(BinSize, 0);
//	////		for ( int i = 0; i < BinSize; i++ )
//	////		{
//	////			CurrModel.FeatureModel[p].BinValue[i]	= PerTrainObj[i] - PerTrainBkg[i];
//	////			CurrModel.FeatureModel[p].Smooth		= __min(CurrModel.FeatureModel[p].Smooth, 0.5 * CurrModel.FeatureModel[p].BinValue[i]);
//	////		}
//	////	}
//	////}
//
//	return	1;
//}

